Compare commits

...
470 Commits
Author SHA1 Message Date
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
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
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
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
Ryan Curtin 259da3d808 Update and release version 2.16.2. 2021-03-25 16:47:25 +01:00
Ryan Curtin 11c2cfe66b Merge pull request #265 from zoq/adam-update-approx
Remove AdamSchafferFunctionN2Test test case
2021-03-24 11:01:04 -04: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
Marcus Edel d5f8b865a7 Update history. 2021-03-22 04:08:26 +01:00
Marcus Edel 4ae22bc9a1 Remove the AdamSchafferFunctionN2Test test from the Adam test suite.
The AdamSchafferFunctionN2Test fails on some specific aarch64 machines, since we are unable to reproduce the issue on other devices, we decided to remove the test from the Adam test suite. The Adam optimizer is still tested against many different functions, which all pass, so we don't think the implementation is wrong. It might be possible to optimize the initial function and optimizer settings to help Adam to converge in certain situations, but since we can't reproduce the issue, it's unclear what those settings are. For more details, see #253.
2021-03-22 02:36:57 +01:00
Ryan Curtin 39aa37d655 Merge pull request #276 from rcurtin/comment-problems
Clarifying comments about test problems
2021-03-21 20:53:01 -04:00
Ryan Curtin e7878f7e3b Update HISTORY. 2021-03-20 14:14:46 -04:00
Ryan Curtin af90625b4a Clarify comments about test problems. 2021-03-20 14:12:27 -04:00
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
Ryan Curtin 472d824dcb Merge pull request #275 from jonpsy/initpoint
InitPoint
2021-03-19 21:05:33 -04:00
NanuSai f4f3c33147 oops 2021-03-19 08:43:20 +05:30
NanuSai b5d3203357 Fonseca Init 2021-03-19 08:38:06 +05:30
Marcus Edel 27f37d19f8 Merge pull request #274 from jonpsy/schaffer
SchafferN1 Initial Point fix.
2021-03-18 14:28:23 -04:00
NanuSai 70ee7947f7 iniital point fix 2021-03-18 21:59:59 +05:30
Marcus Edel ccd7b6c9e6 Merge pull request #271 from matteosecli/patch-2
Swapped default params in AugLagrangian docs.
2021-03-17 22:28:42 -04:00
Matteo Seclì a58d88ef7e Update HISTORY.md 2021-03-15 21:53:30 +01:00
Matteo Seclì 3e7007e791 Swapped default params in AugLagrangian docs 2021-03-14 22:30:55 +01:00
Marcus Edel 706695432c CNE distribution test (#267)
Do not continue if a test was successful.
2021-03-13 16:43:57 -05:00
Ryan Curtin 1e6b538045 Merge pull request #270 from matteosecli/patch-1
Typo in LBFGS() method of AugLagrangian
2021-03-12 08:54:00 -05:00
Ryan Curtin abf539f294 Add changelog entry. 2021-03-11 18:09:15 -05:00
Ryan Curtin 254c8e40f8 Merge branch 'patch-1' of https://github.com/matteosecli/ensmallen into matteosecli-patch-1 2021-03-11 18:08:38 -05:00
Ryan Curtin 1bf557c8a1 Merge pull request #268 from zoq/catch2-update-2.13.4
Catch2 update 2.13.4
2021-03-10 09:24:13 -05:00
Matteo Seclì 9c527470e3 Typo in LBFGS() method of AugLagrangian 2021-03-10 11:19:29 +01:00
Marcus Edel df6240725a Add updated Catch2 license file. 2021-03-07 23:19:54 +01:00
Marcus Edel 33ec784ec2 Update History. 2021-03-07 23:10:49 +01:00
Marcus Edel b886823e03 Update Catch2 to 2.13.4. 2021-03-07 23:06:23 +01:00
Nanubala Gnana Sai 28a37d835b Nits on NSGA2 (#262)
Minor grammar fix.
2021-03-05 17:08:32 -05:00
Ryan Curtin da0d2f03cb Add new block for next release to HISTORY.md. 2021-03-04 14:52:09 -05:00
Ryan Curtin d3b6f676fb Update and release version 2.16.1. 2021-03-04 14:52:09 -05:00
Ryan Curtin a449d5ec28 Merge pull request #259 from rcurtin/warning-fix
Remove unused `const` to fix compilation warnings
2021-03-02 20:07:26 -05:00
Ryan Curtin 23e8be799d Add HISTORY entry. 2021-03-02 10:51:39 -05:00
Ryan Birmingham d13848011c Merge pull request #257 from madhavshah49/master
Spelling and grammatical errors
2021-02-27 16:51:45 -05:00
Ryan Curtin 1755bfff72 Remove unused const. 2021-02-27 16:46:48 -05:00
madhavshah49andMarcus Edel a1d17db8ee Update CONTRIBUTING.md
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-02-27 13:30:20 +05:30
madhavshah49andRyan Birmingham 2fdfe7803e Update CONTRIBUTING.md
Co-authored-by: Ryan Birmingham <birm@rbirm.us>
2021-02-27 13:28:34 +05:30
Ryan Birmingham 95c10690e3 Merge pull request #258 from rcurtin/cne-population-generation
Use normal distribution for CNE initial population generation
2021-02-26 20:36:44 -05:00
Ryan Curtin 1ab6de507f Update history. 2021-02-26 18:54:12 -05:00
Ryan Curtin 3a25abd33e Comment out random seeds. 2021-02-26 18:51:18 -05:00
Ryan Curtin 2b0da57ce1 Use normal distribution not uniform distribution. 2021-02-26 18:50:01 -05:00
madhavshah49andRyan Birmingham 9f614c3536 Update CONTRIBUTING.md
Co-authored-by: Ryan Birmingham <birm@rbirm.us>
2021-02-26 19:42:49 +05:30
madhavshah49andRyan Birmingham 0d12a69bb1 Update CONTRIBUTING.md
Co-authored-by: Ryan Birmingham <birm@rbirm.us>
2021-02-26 19:41:49 +05:30
madhavshah49 6de5c00628 Update LICENSE.txt 2021-02-26 19:36:25 +05:30
madhavshah49andRyan Birmingham 8f60a60458 Update CONTRIBUTING.md
Co-authored-by: Ryan Birmingham <birm@rbirm.us>
2021-02-26 19:28:32 +05:30
madhavshah49 dc9ed15930 Update CONTRIBUTING.md 2021-02-25 23:03:03 +05:30
madhavshah49 ee12ceff17 Update CONTRIBUTING.md 2021-02-25 23:01:45 +05:30
madhavshah49 7a725f8063 Revert "Update README.md"
This reverts commit 3722860270.
2021-02-25 22:53:51 +05:30
madhavshah49 3d1ee2846d Revert "Update CONTRIBUTING.md"
This reverts commit 84323fcd56.
2021-02-25 22:53:19 +05:30
madhavshah49 84323fcd56 Update CONTRIBUTING.md 2021-02-25 22:13:20 +05:30
madhavshah49 3722860270 Update README.md 2021-02-24 20:41:44 +05:30
madhavshah49 cf2c758ecb Update LICENSE.txt 2021-02-24 20:29:46 +05:30
Marcus Edel f987873082 Merge pull request #255 from rcurtin/fix-omp-test
Fix compilation issue when ENS_USE_OPENMP is specified.
2021-02-22 10:51:31 -05:00
Ryan Curtin 17d662b564 Update HISTORY. 2021-02-21 06:54:56 -05:00
Ryan Curtin b29678d234 Fix compilatuon issue when ENS_USE_OPENMP is specified. 2021-02-21 06:48:46 -05:00
Marcus Edel 66244e095b Merge pull request #252 from rcurtin/fix-empty-reports
Fix Report callback when no steps were taken.
2021-02-16 23:14:21 +01:00
Ryan Curtin 50439fb6b2 Slightly more careful handling. 2021-02-15 09:57:00 -05:00
Ryan CurtinandJames J Balamuta 1171f01fe7 Update include/ensmallen_bits/callbacks/report.hpp
Co-authored-by: James J Balamuta <coatless@users.noreply.github.com>
2021-02-15 09:43:49 -05:00
Ryan Curtin aba5e4c5d0 Add new block for next release to HISTORY.md. 2021-02-15 09:28:06 -05:00
Ryan Curtin d5beea9de3 Update and release version 2.16.0. 2021-02-15 09:28:06 -05:00
Ryan Curtin b70284ae70 Handle when no steps were taken. 2021-02-13 16:03:36 -05:00
Ryan Curtin 19a995e9c1 Remove possibly confusing comments. 2021-02-11 18:01:54 -05:00
Ryan Curtin f25c5754d1 Update history. 2021-02-11 18:01:54 -05:00
Ryan Curtin 0e32f02a0e Refactor all tests so that they run for 1k trials without any failures. 2021-02-11 18:01:54 -05:00
Conrad SandersonConrad SandersonJames J BalamutaMarcus EdelRyan Curtin
39069652c6 add short example program; expand README with example installation (#248)
* add short example program; expand README with example installation

Co-authored-by: Conrad Sanderson
Co-authored-by: James J Balamuta
Co-authored-by: Marcus Edel
Co-authored-by: Ryan Curtin
2021-02-02 08:56:40 +01:00
Ryan Curtin cdfae670da Add new block for next release to HISTORY.md. 2020-11-05 12:18:26 -05:00
Ryan Curtin 59288c607e Update and release version 2.15.1. 2020-11-05 12:18:26 -05:00
Yashwant Singh Parihar 7a253d3c3c Merge pull request #239 from coatless/patch-1
Fix include order of traits which reports depends upon
2020-11-05 12:24:37 +05:30
James J BalamutaandMarcus Edel 359bc7ddd3 Update include/ensmallen.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2020-11-04 16:29:52 -06:00
James J Balamuta 8b7731d93c Update HISTORY.md 2020-11-04 01:05:56 -06:00
James J Balamuta 0d4a67b7a0 Update ensmallen.hpp 2020-11-04 01:03:36 -06:00
Marcus Edel e853632bdc Merge pull request #238 from rcurtin/release-2.15.0
Release version 2.15.0: "Why Can't I Manage To Grow Any Plants?"
2020-11-03 21:37:38 +01:00
Ryan Curtin 531e6f4eb3 Add new block for next release to HISTORY.md. 2020-11-01 15:59:28 -05:00
Ryan Curtin f23c780690 Update and release version 2.15.0. 2020-11-01 15:59:28 -05:00
111 changed files with 10850 additions and 4384 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
os: linux
dist: trusty
dist: focal
language: cpp
env:
+4 -4
View File
@@ -22,7 +22,7 @@ merge, to ensure that:
Please do make sure that if you contribute a new optimizer or other new
functionality, that you've added some tests in the `tests/` directory. And if
you are fixing a bug, it's always nice to include a test case if possible to so
you are fixing a bug, it's always nice to include a test case if possible so
that the bug won't happen again.
## Build/test process
@@ -100,7 +100,7 @@ vcpkg install ensmallen:x64-windows
This section describes how to build the **ensmallen** tests from source. **ensmallen** uses CMake as its build system and [Catch2](https://github.com/catchorg/Catch2) as the unit test framework.
First, clone the source code from Github and change into the cloned directory. Or alternatively, you can download the latest relese from the [website](http://ensmallen.org) and extract it.
First, clone the source code from Github and change into the cloned directory. Alternatively, you can download the latest release from the [website](http://ensmallen.org) and extract it.
```bash
$ git clone https://github.com/mlpack/ensmallen
@@ -108,8 +108,8 @@ $ cd ensmallen
# - or -
$ wget http://ensmallen.org/files/ensmallen-2.14.2.tar.gz
$ tar -xvzpf ensmallen-2.14.2.tar.gz
$ wget http://ensmallen.org/files/ensmallen-2.17.0.tar.gz
$ tar -xvzpf ensmallen-2.17.0.tar.gz
$ cd ensmallen-latest
```
+88 -5
View File
@@ -1,16 +1,99 @@
### ensmallen ?.??.?: "???"
###### ????-??-??
### 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
([#267](https://github.com/mlpack/ensmallen/pull/267)).
* Update Catch2 to 2.13.4
([#268](https://github.com/mlpack/ensmallen/pull/268)).
* Fix typos in documentation
([#270](https://github.com/mlpack/ensmallen/pull/270),
[#271](https://github.com/mlpack/ensmallen/pull/271)).
* Add clarifying comments in problems/ implementations
([#276](https://github.com/mlpack/ensmallen/pull/276)).
### ensmallen 2.16.1: "Severely Dented Can Of Polyurethane"
###### 2021-03-02
* Fix test compilation issue when `ENS_USE_OPENMP` is set
([#255](https://github.com/mlpack/ensmallen/pull/255)).
* Fix CNE initial population generation to use normal distribution
([#258](https://github.com/mlpack/ensmallen/pull/258)).
* Fix compilation warnings
([#259](https://github.com/mlpack/ensmallen/pull/259)).
* Remove `AdamSchafferFunctionN2Test` test from Adam test suite to prevent
spurious issue on some aarch64 ([#265](https://github.com/mlpack/ensmallen/pull/259)).
### ensmallen 2.16.0: "Severely Dented Can Of Polyurethane"
###### 2021-02-11
* Expand README with example installation and add simple example program
showing usage of the L-BFGS optimizer
([#248](https://github.com/mlpack/ensmallen/pull/248)).
* Refactor tests to increase stability and reduce random errors
([#249](https://github.com/mlpack/ensmallen/pull/249)).
### ensmallen 2.15.1: "Why Can't I Manage To Grow Any Plants?"
###### 2020-11-05
* Fix include order to ensure traits is loaded before reports
([#239](https://github.com/mlpack/ensmallen/pull/239)).
### ensmallen 2.15.0: "Why Can't I Manage To Grow Any Plants?"
###### 2020-11-01
* Make a few tests more robust
([#228](https://github.com/mlpack/ensmallen/pull/228)).
* Add release date to version information. ([#226](https://github.com/mlpack/ensmallen/pull/226))
* Fix typo in release script
([#236](https://github.com/mlpack/ensmallen/pull/236)).
### ensmallen 2.14.2: "No Direction Home"
###### 2020-08-31
* Fix implementation of fonesca fleming problem function f1 and f2
* Fix implementation of fonesca fleming problem function f1 and f2
type usage and negative signs. ([#223](https://github.com/mlpack/ensmallen/pull/223))
### ensmallen 2.14.1: "No Direction Home"
@@ -37,7 +120,7 @@
* Fix L-BFGS convergence when starting from a minimum
([#201](https://github.com/mlpack/ensmallen/pull/201)).
* Add optimizer summary report callback
* Add optimizer summary report callback
([#213](https://github.com/mlpack/ensmallen/pull/213)).
### ensmallen 2.13.0: "Automatically Automated Automation"
+70 -7
View File
@@ -22,11 +22,73 @@ 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 cmake based installation with root access:
```
mkdir build
cd build
cmake ..
sudo make install
```
Example cmake based installation without root access,
installing into `/home/blah/` (adapt as required):
```
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/home/blah/
make install
```
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
@@ -34,7 +96,8 @@ an updated version of CMake is also available via the EPEL repository via the `c
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
@@ -42,8 +105,8 @@ 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).
* 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.
```
+17
View File
@@ -472,6 +472,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
+3 -2
View File
@@ -876,18 +876,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
+94 -4
View File
@@ -431,12 +431,12 @@ optimizer uses [L-BFGS](#l-bfgs).
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `1000` |
| `double` | **`penaltyThresholdFactor`** | When penalty threshold is updated, set it to this multiplied by the penalty. | `10.0` |
| `double` | **`sigmaUpdateFactor`** | When sigma is updated, multiply it by this. | `0.25` |
| `double` | **`penaltyThresholdFactor`** | When penalty threshold is updated, set it to this multiplied by the penalty. | `0.25` |
| `double` | **`sigmaUpdateFactor`** | When sigma is updated, multiply it by this. | `10.0` |
| `L_BFGS&` | **`lbfgs`** | Internal l-bfgs optimizer. | `L_BFGS()` |
The attributes of the optimizer may also be modified via the member methods
`MaxIterations()`, `PenaltyThresholdFactor()`, `SigmaUpdateFactor()` and `L_BFGS()`.
`MaxIterations()`, `PenaltyThresholdFactor()`, `SigmaUpdateFactor()` and `LBFGS()`.
<details open>
<summary>Click to collapse/expand example code.
@@ -1563,6 +1563,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 +1709,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>
+70
View File
@@ -0,0 +1,70 @@
// Example implementation of an objective function class for linear regression
// and usage of the L-BFGS optimizer.
//
// Compilation:
// g++ example.cpp -o example -O3 -larmadillo
#include <iostream>
#include <armadillo>
#include <ensmallen.hpp>
class LinearRegressionFunction
{
public:
LinearRegressionFunction(arma::mat& X, arma::vec& y) : X(X), y(y) { }
double EvaluateWithGradient(const arma::mat& theta, arma::mat& gradient)
{
const arma::vec tmp = X.t() * theta - y;
gradient = 2 * X * tmp;
return arma::dot(tmp,tmp);
}
private:
const arma::mat& X;
const arma::vec& y;
};
int main(int argc, char** argv)
{
if (argc < 3)
{
std::cout << "usage: " << argv[0] << " n_dims n_points" << std::endl;
return -1;
}
int n_dims = atoi(argv[1]);
int n_points = atoi(argv[2]);
// generate noisy dataset with a slight linear pattern
arma::mat X(n_dims, n_points, arma::fill::randu);
arma::vec y( n_points, arma::fill::randu);
for (size_t i = 0; i < n_points; ++i)
{
double a = arma::randu();
X(1, i) += a;
y(i) += a;
}
LinearRegressionFunction lrf(X, y);
// create a Limited-memory BFGS optimizer object with default parameters
ens::L_BFGS opt;
opt.MaxIterations() = 10;
// initial point (uniform random)
arma::vec theta(n_dims, arma::fill::randu);
opt.Optimize(lrf, theta);
// theta now contains the optimized parameters
theta.print("theta:");
return 0;
}
+7 -2
View File
@@ -65,12 +65,18 @@
#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/
// Callbacks.
#include "ensmallen_bits/callbacks/callbacks.hpp"
#include "ensmallen_bits/callbacks/early_stop_at_min_loss.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"
@@ -90,8 +96,6 @@
#include "ensmallen_bits/eve/eve.hpp"
#include "ensmallen_bits/ftml/ftml.hpp"
#include "ensmallen_bits/function.hpp" // TODO: should move to function/
#include "ensmallen_bits/fw/frank_wolfe.hpp"
#include "ensmallen_bits/gradient_descent/gradient_descent.hpp"
#include "ensmallen_bits/grid_search/grid_search.hpp"
@@ -99,6 +103,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"
+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
@@ -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
+25 -2
View File
@@ -149,6 +149,26 @@ class Report
output << coordinates.n_cols << std::endl;
output << std::endl;
// If we did not take any steps, at least fill what the initial objective
// was.
const bool tookStep = (objectives.size() > 0);
if (objectives.size() == 0 && evaluateCalls > 0)
{
objectives.push_back(objective);
timings.push_back(optimizationTimer.toc());
}
else if (evaluateCalls == 0)
{
// It's not entirely clear how to compute the objective (since the
// function could implement many different ways of evaluating the
// objective), so issue an error and return.
output << "Objective never computed. Did the optimization fail?"
<< std::endl;
PrettyPrintElement("Time (in seconds):", 30);
output << optimizationTimer.toc() << std::endl;
return;
}
output << "Loss:" << std::endl;
PrettyPrintElement("Initial", 30);
output << objectives[0] << std::endl;
@@ -166,7 +186,10 @@ class Report
output << optimizerStream.str();
PrettyPrintElement("Iterations:", 30);
output << objectives.size() << std::endl;
if (tookStep)
output << objectives.size() << std::endl;
else
output << "0 (No steps taken! Did the optimization fail?)" << std::endl;
if (epochCalls > 0)
{
@@ -183,7 +206,7 @@ class Report
output << stepsizes.back() << std::endl;
}
if (hasGradient)
if (hasGradient && gradientsNorm.size() > 0)
{
PrettyPrintElement("Coordinates max. norm:", 30);
output << *std::max_element(std::begin(gradientsNorm),
@@ -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,
@@ -365,6 +367,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
@@ -93,7 +93,7 @@ typename MatType::elem_type CNE::Optimize(ArbitraryFunctionType& function,
std::vector<BaseMatType> population;
for (size_t i = 0 ; i < populationSize; ++i)
{
population.push_back(arma::randu<BaseMatType>(iterate.n_rows,
population.push_back(arma::randn<BaseMatType>(iterate.n_rows,
iterate.n_cols) + iterate);
}
+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 14
#define ENS_VERSION_PATCH 2
#define ENS_VERSION_MINOR 17
#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 "No Direction Home"
#define ENS_VERSION_NAME "Pachis Din Me Pesa Double"
// Incorporate the date the version was released.
#define ENS_VERSION_YEAR "2020"
#define ENS_VERSION_MONTH "09"
#define ENS_VERSION_DAY "05"
#define ENS_VERSION_YEAR "2021"
#define ENS_VERSION_MONTH "07"
#define ENS_VERSION_DAY "06"
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;
@@ -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
+127 -77
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,11 +76,22 @@ 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);
// Check if lower bound is a vector of a single dimension.
// 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);
@@ -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;
@@ -59,10 +59,6 @@ class AckleyFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-5.0; 5.0"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -116,6 +112,22 @@ class AckleyFunction
//! Modify the value used for numerical stability.
double& Epsilon() { return epsilon; }
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("0.02; 0.02"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("0.0; 0.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
private:
//! The value of the multiplicative constant.
double c;
@@ -52,10 +52,6 @@ class BealeFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-4.5; 4.5"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -98,6 +94,22 @@ class BealeFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("2.8; 0.35"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("3.0; 0.5"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -52,10 +52,6 @@ class BoothFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-9; -9"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -98,6 +94,22 @@ class BoothFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-9; -9"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("1.0; 3.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -57,10 +57,6 @@ class BukinFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-10; -2.0"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -109,6 +105,22 @@ class BukinFunction
//! Modify the value used for numerical stability.
double& Epsilon() { return epsilon; }
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-10; -2.0"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("-10.0; 1.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
private:
//! The value used for numerical stability.
double epsilon;
@@ -53,10 +53,6 @@ class ColvilleFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-5; 3; 1; -9"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -99,6 +95,22 @@ class ColvilleFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient) const;
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-5; 3; 1; -9"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("1; 1; 1; 1"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -57,10 +57,6 @@ class CrossInTrayFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("0; 0"); }
/*
* Evaluate a function for a particular batch-size.
*
@@ -80,6 +76,14 @@ class CrossInTrayFunction
*/
template<typename MatType>
typename MatType::elem_type Evaluate(const MatType& coordinates) const;
// Note: GetInitialPoint() is not required for using ensmallen to optimize
// this function! It is specifically used as a convenience just for
// ensmallen's testing infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("0; 0"); }
};
} // namespace test
@@ -52,10 +52,6 @@ class DropWaveFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("0.5; 0.5"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -98,6 +94,22 @@ class DropWaveFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("0.5; 0.5"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("0.0; 0.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -52,10 +52,6 @@ class EasomFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-90.0; 90.0"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -98,6 +94,22 @@ class EasomFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("2.9; 2.9"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("3.14; 3.14"); }
//! Get the final objective.
double GetFinalObjective() const { return -1.0; }
};
} // namespace test
@@ -53,10 +53,6 @@ class EggholderFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-333; -333"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -99,6 +95,22 @@ class EggholderFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-333; -333"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("512; 404.2319"); }
//! Get the final objective.
double GetFinalObjective() const { return -959.6407; }
};
} // namespace test
@@ -64,7 +64,10 @@ class FonsecaFlemingFunction
//! Get the starting point.
MatType GetInitialPoint()
{
return arma::vec(numVariables, 1, arma::fill::zeros);
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
return arma::Col<ElemType>(numVariables, 1, arma::fill::zeros);
}
struct ObjectiveA
@@ -61,13 +61,6 @@ class GeneralizedRosenbrockFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return n - 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
const MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
/**
* Evaluate a function for a particular batch-size.
*
@@ -111,6 +104,28 @@ class GeneralizedRosenbrockFunction
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient) const;
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
const MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
//! Get the final point.
template<typename MatType = arma::mat>
const MatType GetFinalPoint() const
{
return arma::ones<MatType>(initialPoint.n_rows, initialPoint.n_cols);
}
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
private:
//! Locally-stored Initial point.
arma::mat initialPoint;
@@ -61,10 +61,6 @@ class GoldsteinPriceFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-2; 2"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -107,6 +103,22 @@ class GoldsteinPriceFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("0.2; -0.5"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("0.0; -1.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 3.0; }
};
} // namespace test
@@ -25,10 +25,6 @@ class GDTestFunction
//! Nothing to do for the constructor.
GDTestFunction() { }
//! Get the starting point.
template<typename MatType>
MatType GetInitialPoint() const { return MatType("1; 3; 2"); }
//! Evaluate a function.
template<typename MatType>
typename MatType::elem_type Evaluate(const MatType& coordinates) const;
@@ -36,6 +32,22 @@ class GDTestFunction
//! Evaluate the gradient of a function.
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient) const;
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType>
MatType GetInitialPoint() const { return MatType("1; 3; 2"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("0; 0; 0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -48,10 +48,6 @@ class LevyFunctionN13
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-10; 10"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -94,6 +90,22 @@ class LevyFunctionN13
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("0.9; 1.1"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("1.0; 1.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -52,10 +52,6 @@ class MatyasFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-3; 3"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -98,6 +94,22 @@ class MatyasFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-3; 3"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("0.0; 0.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -52,10 +52,6 @@ class McCormickFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-2; 4"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -98,6 +94,22 @@ class McCormickFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-2; 4"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("-0.54719; -1.54719"); }
//! Get the final objective.
double GetFinalObjective() const { return -1.9133; }
};
} // namespace test
@@ -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
@@ -44,24 +44,17 @@ class RastriginFunction
*
* @param n Number of dimensions for the function.
*/
RastriginFunction(const size_t n);
RastriginFunction(const size_t n = 2);
/**
* Shuffle the order of function visitation. This may be called by the
* optimizer.
*/
void Shuffle();
void Shuffle();
//! Return 1 (the number of functions).
size_t NumFunctions() const { return n; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
/**
* Evaluate a function for a particular batch-size.
*
@@ -104,6 +97,29 @@ class RastriginFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const
{
return arma::zeros<MatType>(initialPoint.n_rows, initialPoint.n_cols);
}
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
private:
//! Number of dimensions for the function.
size_t n;
@@ -55,16 +55,6 @@ class RosenbrockFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
MatType m(2, 1);
m[0] = -1.2;
m[1] = 1.0;
return m;
}
/**
* Evaluate a function for a particular batch-size.
*
@@ -114,6 +104,22 @@ class RosenbrockFunction
template<typename MatType, typename GradType>
typename MatType::elem_type EvaluateWithGradient(const MatType& coordinates,
GradType& gradient) const;
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-1.2; 1.0"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("1.0; 1.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -39,13 +39,6 @@ class RosenbrockWoodFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
const MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
/**
* Evaluate a function for a particular batch-size.
*
@@ -89,6 +82,28 @@ class RosenbrockWoodFunction
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient) const;
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
const MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const
{
return arma::ones<MatType>(initialPoint.n_rows, initialPoint.n_cols);
}
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
private:
//! Locally-stored initial point.
arma::mat initialPoint;
@@ -63,7 +63,10 @@ class SchafferFunctionN1
//! Get the starting point.
MatType GetInitialPoint()
{
return arma::vec(numVariables, 1, arma::fill::zeros);
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
return arma::Col<ElemType>(numVariables, 1, arma::fill::zeros);
}
struct ObjectiveA
@@ -53,10 +53,6 @@ class SchafferFunctionN2
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-100; 100"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -99,6 +95,22 @@ class SchafferFunctionN2
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-100; 100"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("0.0; 0.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -55,13 +55,6 @@ class SchwefelFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return n; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
/**
* Evaluate a function for a particular batch-size.
*
@@ -104,6 +97,31 @@ class SchwefelFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const
{
MatType result(initialPoint.n_rows, initialPoint.n_cols, arma::fill::none);
result.fill(420.9687);
return result;
}
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
private:
//! Number of dimensions for the function.
size_t n;
@@ -37,10 +37,6 @@ class SGDTestFunction
//! Return 3 (the number of functions).
size_t NumFunctions() const { return 3; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("6; -45.6; 6.2"); }
//! Evaluate a function for a particular batch-size.
template<typename MatType>
typename MatType::elem_type Evaluate(const MatType& coordinates,
@@ -53,6 +49,22 @@ class SGDTestFunction
const size_t begin,
GradType& gradient,
const size_t batchSize) const;
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("6; -45.6; 6.2"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("0.0; 0.0; 0.0"); }
//! Get the final objective.
double GetFinalObjective() const { return -1.0; }
};
} // namespace test
@@ -32,10 +32,6 @@ class SparseTestFunction
//! Return 4 (the number of features).
size_t NumFeatures() const { return 4; }
//! Get the starting point.
template<typename MatType>
MatType GetInitialPoint() const { return MatType("0 0 0 0;"); }
//! Evaluate a function.
template<typename MatType>
typename MatType::elem_type Evaluate(const MatType& coordinates,
@@ -61,6 +57,22 @@ class SparseTestFunction
const size_t j,
GradType& gradient) const;
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType>
MatType GetInitialPoint() const { return MatType("0 0 0 0;"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("2.0 1.0 1.5 4.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 123.75; }
private:
// Each quadratic polynomial is monic. The intercept and coefficient of the
// first order term is stored.
@@ -45,7 +45,7 @@ class SphereFunction
*
* @param n Number of dimensions for the function.
*/
SphereFunction(const size_t n);
SphereFunction(const size_t n = 2);
/**
* Shuffle the order of function visitation. This may be called by the
@@ -56,13 +56,6 @@ class SphereFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return n; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
/**
* Evaluate a function for a particular batch-size.
*
@@ -106,6 +99,28 @@ class SphereFunction
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const
{
return arma::zeros<MatType>(initialPoint.n_rows, initialPoint.n_cols);
}
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
private:
//! Number of dimensions for the function.
size_t n;
@@ -46,7 +46,7 @@ class StyblinskiTangFunction
*
* @param n Number of dimensions for the function.
*/
StyblinskiTangFunction(const size_t n);
StyblinskiTangFunction(const size_t n = 2);
/**
* Shuffle the order of function visitation. This may be called by the
@@ -57,13 +57,6 @@ class StyblinskiTangFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return n; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
/**
* Evaluate a function for a particular batch-size.
*
@@ -107,6 +100,31 @@ class StyblinskiTangFunction
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const
{
return arma::conv_to<MatType>::from(initialPoint);
}
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const
{
MatType result(initialPoint.n_rows, initialPoint.n_cols);
for (size_t i = 0; i < result.n_elem; ++i)
result[i] = -2.903534;
return result;
}
//! Get the final objective.
double GetFinalObjective() const { return -39.16599 * n; }
private:
//! Number of dimensions for the function.
size_t n;
@@ -58,10 +58,6 @@ class ThreeHumpCamelFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-4.5; 4.5"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -104,6 +100,22 @@ class ThreeHumpCamelFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient);
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("1; 1"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("0.0; 0.0"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -59,10 +59,6 @@ class WoodFunction
//! Return 1 (the number of functions).
size_t NumFunctions() const { return 1; }
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-3; -1; -3; -1"); }
/**
* Evaluate a function for a particular batch-size.
*
@@ -105,6 +101,22 @@ class WoodFunction
*/
template<typename MatType, typename GradType>
void Gradient(const MatType& coordinates, GradType& gradient) const;
// Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not
// required for using ensmallen to optimize this function! They are
// specifically used as a convenience just for ensmallen's testing
// infrastructure.
//! Get the starting point.
template<typename MatType = arma::mat>
MatType GetInitialPoint() const { return MatType("-3; -1; -3; -1"); }
//! Get the final point.
template<typename MatType = arma::mat>
MatType GetFinalPoint() const { return MatType("1; 1; 1; 1"); }
//! Get the final objective.
double GetFinalObjective() const { return 0.0; }
};
} // namespace test
@@ -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
+1 -1
View File
@@ -76,7 +76,7 @@ typename MatType::elem_type SA<CoolingScheduleType>::Optimize(
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;
@@ -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. */
}
@@ -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
+3 -2
View File
@@ -23,6 +23,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
@@ -47,7 +48,7 @@ set(ENSMALLEN_TESTS_SOURCES
)
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 +60,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})
+7 -43
View File
@@ -20,31 +20,19 @@ using namespace ens::test;
*/
TEST_CASE("AdaBoundSphereFunctionTest", "[AdaBoundTest]")
{
SphereFunction f(2);
AdaBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 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));
FunctionTest<SphereFunction>(optimizer, 0.5, 0.1);
}
/**
* Test the AdaBound optimizer on the Sphere function with arma::fmat.
*/
TEST_CASE("AdaBoundphereFunctionTestFMat", "[AdaBoundTest]")
TEST_CASE("AdaBoundSphereFunctionTestFMat", "[AdaBoundTest]")
{
SphereFunction f(2);
AdaBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 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));
FunctionTest<SphereFunction, arma::fmat>(optimizer, 0.5, 0.1);
}
/**
@@ -52,15 +40,9 @@ TEST_CASE("AdaBoundphereFunctionTestFMat", "[AdaBoundTest]")
*/
TEST_CASE("AMSBoundSphereFunctionTest", "[AdaBoundTest]")
{
SphereFunction f(2);
AMSBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 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));
FunctionTest<SphereFunction, arma::mat>(optimizer, 0.5, 0.1);
}
/**
@@ -68,15 +50,9 @@ TEST_CASE("AMSBoundSphereFunctionTest", "[AdaBoundTest]")
*/
TEST_CASE("AMSBoundphereFunctionTestFMat", "[AdaBoundTest]")
{
SphereFunction f(2);
AMSBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 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));
FunctionTest<SphereFunction, arma::fmat>(optimizer, 0.5, 0.1);
}
#if ARMA_VERSION_MAJOR > 9 ||\
@@ -87,15 +63,9 @@ TEST_CASE("AMSBoundphereFunctionTestFMat", "[AdaBoundTest]")
*/
TEST_CASE("AdaBoundSphereFunctionTestSpMat", "[AdaBoundTest]")
{
SphereFunction f(2);
AdaBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000,
1e-3, false);
arma::sp_mat coordinates = f.GetInitialPoint<arma::sp_mat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.1));
FunctionTest<SphereFunction, arma::sp_mat>(optimizer, 0.5, 0.1);
}
/**
@@ -120,15 +90,9 @@ TEST_CASE("AdaBoundSphereFunctionTestSpMatDenseGradient", "[AdaBoundTest]")
*/
TEST_CASE("AMSBoundSphereFunctionTestSpMat", "[AdaBoundTest]")
{
SphereFunction f(2);
AMSBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000,
1e-3, false);
arma::sp_mat coordinates = f.GetInitialPoint<arma::sp_mat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.1));
FunctionTest<SphereFunction, arma::sp_mat>(optimizer, 0.5, 0.1);
}
/**
+2 -76
View File
@@ -18,71 +18,13 @@
using namespace ens;
using namespace ens::test;
/**
* Tests the Adadelta optimizer using a simple test function.
*/
TEST_CASE("SimpleAdaDeltaTestFunction", "[AdaDeltaTest]")
{
SGDTestFunction f;
AdaDelta optimizer(1.0, 1, 0.05, 1e-6, 5000000, 1e-15, true, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.003));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.003));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.003));
}
/**
* Run AdaDelta on logistic regression and make sure the results are acceptable.
*/
TEST_CASE("AdaDeltaLogisticRegressionTest", "[AdaDeltaTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
AdaDelta adaDelta;
arma::mat coordinates = lr.GetInitialPoint();
adaDelta.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
}
/**
* Tests the Adadelta optimizer using a simple test function with arma::fmat as
* the type.
*/
TEST_CASE("SimpleAdaDeltaTestFunctionFMat", "[AdaDeltaTest]")
{
size_t trials = 3;
SGDTestFunction f;
arma::fmat coordinates;
for (size_t i = 0; i < trials; ++i)
{
coordinates = f.GetInitialPoint<arma::fmat>();
AdaDelta optimizer(2.0, 1, 0.05, 1e-6, 5000000, 1e-8, true, true);
optimizer.Optimize(f, coordinates);
if (arma::max(arma::vectorise(arma::abs(coordinates))) < 0.01f)
break;
}
REQUIRE(coordinates(0) == Approx(0.0f).margin(0.01));
REQUIRE(coordinates(1) == Approx(0.0f).margin(0.01));
REQUIRE(coordinates(2) == Approx(0.0f).margin(0.01));
LogisticRegressionFunctionTest(adaDelta, 0.003, 0.006, 1);
}
/**
@@ -91,22 +33,6 @@ TEST_CASE("SimpleAdaDeltaTestFunctionFMat", "[AdaDeltaTest]")
*/
TEST_CASE("AdaDeltaLogisticRegressionTestFMat", "[AdaDeltaTest]")
{
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);
AdaDelta adaDelta;
arma::fmat coordinates = lr.GetInitialPoint();
adaDelta.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(adaDelta, 0.003, 0.006, 1);
}
+2 -75
View File
@@ -17,70 +17,13 @@
using namespace ens;
using namespace ens::test;
/**
* Tests the Adagrad optimizer using a simple test function.
*/
TEST_CASE("SimpleAdaGradTestFunction", "[AdaGradTest]")
{
SGDTestFunction f;
AdaGrad optimizer(0.99, 1, 1e-8, 5000000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.003));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.003));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.003));
}
/**
* Run AdaGrad on logistic regression and make sure the results are acceptable.
*/
TEST_CASE("AdaGradLogisticRegressionTest", "[AdaGradTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
AdaGrad adagrad(0.99, 32, 1e-8, 5000000, 1e-9, true);
arma::mat coordinates = lr.GetInitialPoint();
adagrad.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
}
/**
* Tests the Adagrad optimizer using a simple test function with arma::fmat.
*/
TEST_CASE("SimpleAdaGradTestFunctionFMat", "[AdaGradTest]")
{
size_t trials = 3;
SGDTestFunction f;
arma::fmat coordinates;
for (size_t i = 0; i < trials; ++i)
{
coordinates = f.GetInitialPoint<arma::fmat>();
AdaGrad optimizer(0.99, 1, 1e-8, 5000000, 1e-9, true);
optimizer.Optimize(f, coordinates);
if (arma::max(arma::vectorise(arma::abs(coordinates))) < 0.01f)
break;
}
REQUIRE(coordinates(0) == Approx(0.0f).margin(0.01));
REQUIRE(coordinates(1) == Approx(0.0f).margin(0.01));
REQUIRE(coordinates(2) == Approx(0.0f).margin(0.01));
LogisticRegressionFunctionTest(adagrad, 0.003, 0.006);
}
/**
@@ -88,22 +31,6 @@ TEST_CASE("SimpleAdaGradTestFunctionFMat", "[AdaGradTest]")
*/
TEST_CASE("AdaGradLogisticRegressionTestFMat", "[AdaGradTest]")
{
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);
AdaGrad adagrad(0.99, 32, 1e-8, 5000000, 1e-9, true);
arma::fmat coordinates = lr.GetInitialPoint();
adagrad.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(adagrad, 0.003, 0.006);
}
+27 -448
View File
@@ -25,14 +25,8 @@ using namespace ens::test;
*/
TEST_CASE("AdamSphereFunctionTest", "[AdamTest]")
{
SphereFunction f(2);
Adam 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));
FunctionTest<SphereFunction>(optimizer, 0.5, 0.2);
}
/**
@@ -40,14 +34,8 @@ TEST_CASE("AdamSphereFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamSphereFunctionTestFMat", "[AdamTest]")
{
SphereFunction f(2);
Adam 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));
FunctionTest<SphereFunction, arma::fmat>(optimizer, 0.5, 0.2);
}
#if ARMA_VERSION_MAJOR > 9 ||\
@@ -58,14 +46,8 @@ TEST_CASE("AdamSphereFunctionTestFMat", "[AdamTest]")
*/
TEST_CASE("AdamSphereFunctionTestSpMat", "[AdamTest]")
{
SphereFunction f(2);
Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false);
arma::sp_mat coordinates = f.GetInitialPoint<arma::sp_mat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.1));
FunctionTest<SphereFunction, arma::sp_mat>(optimizer, 0.5, 0.2);
}
/**
@@ -91,14 +73,8 @@ TEST_CASE("AdamSphereFunctionTestSpMatDenseGradient", "[AdamTest]")
*/
TEST_CASE("AdamStyblinskiTangFunctionTest", "[AdamTest]")
{
StyblinskiTangFunction f(2);
Adam 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(-2.9).epsilon(0.01)); // 1% error tolerance.
REQUIRE(coordinates(1) == Approx(-2.9).epsilon(0.01)); // 1% error tolerance.
FunctionTest<StyblinskiTangFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -106,15 +82,8 @@ TEST_CASE("AdamStyblinskiTangFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamMcCormickFunctionTest", "[AdamTest]")
{
McCormickFunction f;
Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
// 3% error tolerance.
REQUIRE(coordinates(0) == Approx(-0.547).epsilon(0.03));
REQUIRE(coordinates(1) == Approx(-1.547).epsilon(0.03));
FunctionTest<McCormickFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -122,17 +91,8 @@ TEST_CASE("AdamMcCormickFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamMatyasFunctionTest", "[AdamTest]")
{
MatyasFunction f;
Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
// 3% error tolerance.
REQUIRE((std::trunc(100.0 * coordinates(0)) / 100.0) ==
Approx(0.0).epsilon(0.003));
REQUIRE((std::trunc(100.0 * coordinates(1)) / 100.0) ==
Approx(0.0).epsilon(0.003));
FunctionTest<MatyasFunction>(optimizer, 0.1, 0.01);
}
/**
@@ -140,17 +100,8 @@ TEST_CASE("AdamMatyasFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamEasomFunctionTest", "[AdamTest]")
{
EasomFunction f;
Adam optimizer(0.2, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false);
arma::mat coordinates = arma::mat("2.9; 2.9");
optimizer.Optimize(f, coordinates);
// 5% error tolerance.
REQUIRE((std::trunc(100.0 * coordinates(0)) / 100.0) ==
Approx(3.14).epsilon(0.005));
REQUIRE((std::trunc(100.0 * coordinates(1)) / 100.0) ==
Approx(3.14).epsilon(0.005));
FunctionTest<EasomFunction>(optimizer, 1.5, 0.01);
}
/**
@@ -158,77 +109,18 @@ TEST_CASE("AdamEasomFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamBoothFunctionTest", "[AdamTest]")
{
BoothFunction f;
Adam optimizer(1e-1, 1, 0.7, 0.999, 1e-8, 500000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(1.0).epsilon(0.002));
REQUIRE(coordinates(1) == Approx(3.0).epsilon(0.002));
FunctionTest<BoothFunction>(optimizer);
}
/**
* Tests the Adam optimizer using a simple test function.
*/
TEST_CASE("SimpleAdamTestFunction", "[AdamTest]")
{
SGDTestFunction f;
Adam optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.3));
}
/**
* Tests the AdaMax optimizer using a simple test function.
*/
TEST_CASE("SimpleAdaMaxTestFunction", "[AdamTest]")
{
SGDTestFunction f;
AdaMax optimizer(2e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.3));
}
/**
* Tests the AMSGrad optimizer using a simple test function.
*/
TEST_CASE("SimpleAMSGradTestFunction", "[AdamTest]")
{
SGDTestFunction f;
AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.3));
}
/**
* Test the AMSGrad optimizer on the Sphere function with arma::fmat.
*/
TEST_CASE("AMSGradSphereFunctionTestFMat", "[AdamTest]")
{
SphereFunction f(2);
AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true);
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));
FunctionTest<SphereFunction, arma::fmat>(optimizer, 0.5, 0.1);
}
#if ARMA_VERSION_MAJOR > 9 || \
@@ -239,14 +131,8 @@ TEST_CASE("AMSGradSphereFunctionTestFMat", "[AdamTest]")
*/
TEST_CASE("AMSGradSphereFunctionTestSpMat", "[AdamTest]")
{
SphereFunction f(2);
AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true);
arma::sp_mat coordinates = f.GetInitialPoint<arma::sp_mat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.1));
FunctionTest<SphereFunction, arma::sp_mat>(optimizer, 0.5, 0.1);
}
/**
@@ -272,24 +158,8 @@ TEST_CASE("AMSGradSphereFunctionTestSpMatDenseGradient", "[AdamTest]")
*/
TEST_CASE("AdamLogisticRegressionTest", "[AdamTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
Adam adam;
arma::mat coordinates = lr.GetInitialPoint();
adam.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(adam, 0.003, 0.006);
}
/**
@@ -297,24 +167,8 @@ TEST_CASE("AdamLogisticRegressionTest", "[AdamTest]")
*/
TEST_CASE("AdaMaxLogisticRegressionTest", "[AdamTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
AdaMax adamax(1e-3, 1, 0.9, 0.999, 1e-8, 5000000, 1e-9, true);
arma::mat coordinates = lr.GetInitialPoint();
adamax.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(adamax, 0.003, 0.006);
}
/**
@@ -322,40 +176,8 @@ TEST_CASE("AdaMaxLogisticRegressionTest", "[AdamTest]")
*/
TEST_CASE("AMSGradLogisticRegressionTest", "[AdamTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
AMSGrad amsgrad(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true);
arma::mat coordinates = lr.GetInitialPoint();
amsgrad.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
}
/**
* Tests the Nadam optimizer using a simple test function.
*/
TEST_CASE("SimpleNadamTestFunction", "[AdamTest]")
{
SGDTestFunction f;
Nadam optimizer(1e-3, 1, 0.9, 0.99, 1e-8, 500000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.3));
LogisticRegressionFunctionTest(amsgrad, 0.003, 0.006);
}
/**
@@ -363,40 +185,8 @@ TEST_CASE("SimpleNadamTestFunction", "[AdamTest]")
*/
TEST_CASE("NadamLogisticRegressionTest", "[AdamTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
Nadam nadam;
arma::mat coordinates = lr.GetInitialPoint();
nadam.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
}
/**
* Tests the NadaMax optimizer using a simple test function.
*/
TEST_CASE("SimpleNadaMaxTestFunction", "[AdamTest]")
{
SGDTestFunction f;
NadaMax optimizer(1e-3, 1, 0.9, 0.99, 1e-8, 500000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.3));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.3));
LogisticRegressionFunctionTest(nadam, 0.003, 0.006);
}
/**
@@ -404,101 +194,18 @@ TEST_CASE("SimpleNadaMaxTestFunction", "[AdamTest]")
*/
TEST_CASE("NadaMaxLogisticRegressionTest", "[AdamTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
NadaMax nadamax(1e-3, 1, 0.9, 0.999, 1e-8, 5000000, 1e-9, true);
arma::mat coordinates = lr.GetInitialPoint();
nadamax.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(nadamax, 0.003, 0.006);
}
/**
* Tests the OptimisticAdam optimizer using a simple test function.
*/
TEST_CASE("SimpleOptimisticAdamTestFunction", "[AdamTest]")
{
// Sometimes this test can fail randomly, so we allow it to run up to three
// times.
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
SGDTestFunction f;
OptimisticAdam optimizer(1e-2, 1, 0.9, 0.99, 1e-8);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
success = (coordinates(0) == Approx(0.0).margin(0.3)) &&
(coordinates(1) == Approx(0.0).margin(0.3)) &&
(coordinates(2) == Approx(0.0).margin(0.3));
if (success)
break;
}
REQUIRE(success == true);
}
/**
* Run OptimisticAdam on logistic regression and make sure the results are acceptable.
* Run OptimisticAdam on logistic regression and make sure the results are
* acceptable.
*/
TEST_CASE("OptimisticAdamLogisticRegressionTest", "[AdamTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
OptimisticAdam optimisticAdam;
arma::mat coordinates = lr.GetInitialPoint();
optimisticAdam.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
}
/**
* Tests the Padam optimizer using a simple test function.
*/
TEST_CASE("SimplePadamTestFunction", "[AdamTest]")
{
// Sometimes this test can fail randomly, so we allow it to run up to three
// times.
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
SGDTestFunction f;
Padam optimizer(1e-2, 1, 0.9, 0.99, 0.25, 1e-8);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
success = (coordinates(0) == Approx(0.0).margin(0.3)) &&
(coordinates(1) == Approx(0.0).margin(0.3)) &&
(coordinates(2) == Approx(0.0).margin(0.3));
if (success)
break;
}
REQUIRE(success == true);
LogisticRegressionFunctionTest(optimisticAdam, 0.003, 0.006);
}
/**
@@ -506,41 +213,8 @@ TEST_CASE("SimplePadamTestFunction", "[AdamTest]")
*/
TEST_CASE("PadamLogisticRegressionTest", "[AdamTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
Padam optimizer;
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
}
/**
* Tests the QHadam optimizer using a simple test function.
*/
TEST_CASE("SimpleQHAdamTestFunction", "[AdamTest]")
{
SGDTestFunction f;
QHAdam optimizer(0.02, 32, 0.6, 0.9, 0.9, 0.999, 1e-8, 200000, 1e-7, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
bool success = (coordinates(0) == Approx(0.0).margin(0.3)) &&
(coordinates(1) == Approx(0.0).margin(0.3)) &&
(coordinates(2) == Approx(0.0).margin(0.3));
REQUIRE(success == true);
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
@@ -548,24 +222,8 @@ TEST_CASE("SimpleQHAdamTestFunction", "[AdamTest]")
*/
TEST_CASE("QHAdamLogisticRegressionTest", "[AdamTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
QHAdam optimizer;
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
@@ -574,24 +232,8 @@ TEST_CASE("QHAdamLogisticRegressionTest", "[AdamTest]")
*/
TEST_CASE("QHAdamLogisticRegressionFMatTest", "[AdamTest]")
{
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);
QHAdam optimizer;
arma::fmat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const float acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.03)); // 3% error tolerance.
const float testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.06)); // 6% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.03, 0.06);
}
#if ARMA_VERSION_MAJOR > 9 ||\
@@ -603,24 +245,8 @@ TEST_CASE("QHAdamLogisticRegressionFMatTest", "[AdamTest]")
*/
TEST_CASE("QHAdamLogisticRegressionSpMatTest", "[AdamTest]")
{
arma::sp_mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<arma::sp_mat> lr(shuffledData, shuffledResponses, 0.5);
QHAdam optimizer;
arma::sp_mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::sp_mat>(optimizer, 0.003, 0.006);
}
#endif
@@ -632,14 +258,8 @@ TEST_CASE("QHAdamLogisticRegressionSpMatTest", "[AdamTest]")
*/
TEST_CASE("AdamAckleyFunctionTest", "[AdamTest]")
{
AckleyFunction f;
Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-7, false);
arma::mat coordinates = arma::mat("0.02; 0.02");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.001));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.001));
FunctionTest<AckleyFunction>(optimizer);
}
/**
@@ -649,14 +269,8 @@ TEST_CASE("AdamAckleyFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamBealeFunctionTest", "[AdamTest]")
{
BealeFunction f;
Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-7, false);
arma::mat coordinates = arma::mat("2.8; 0.35");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(3.0).margin(0.01));
REQUIRE(coordinates(1) == Approx(0.5).margin(0.01));
FunctionTest<BealeFunction>(optimizer, 0.1, 0.01);
}
/**
@@ -666,14 +280,8 @@ TEST_CASE("AdamBealeFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamGoldsteinPriceFunctionTest", "[AdamTest]")
{
GoldsteinPriceFunction f;
Adam optimizer(0.0001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false);
arma::mat coordinates = arma::mat("0.2; -0.5");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.01));
REQUIRE(coordinates(1) == Approx(-1).margin(0.01));
FunctionTest<GoldsteinPriceFunction>(optimizer, 0.1, 0.01);
}
/**
@@ -683,14 +291,8 @@ TEST_CASE("AdamGoldsteinPriceFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamLevyFunctionTest", "[AdamTest]")
{
LevyFunctionN13 f;
Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false);
arma::mat coordinates = arma::mat("0.9; 1.1");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(1).margin(0.01));
REQUIRE(coordinates(1) == Approx(1).margin(0.01));
FunctionTest<LevyFunctionN13>(optimizer, 0.1, 0.01);
}
/**
@@ -717,29 +319,6 @@ TEST_CASE("AdamHimmelblauFunctionTest", "[AdamTest]")
*/
TEST_CASE("AdamThreeHumpCamelFunctionTest", "[AdamTest]")
{
ThreeHumpCamelFunction f;
Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false);
arma::mat coordinates = arma::mat("1; 1");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.01));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.01));
}
/**
* Test the Adam optimizer on Schaffer function N.2.
* This is to test Schaffer function N.2 and not Adam.
* This test will be removed later.
*/
TEST_CASE("AdamSchafferFunctionN2Test", "[AdamTest]")
{
SchafferFunctionN2 f;
Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false);
arma::mat coordinates = arma::mat("1; 1");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.01));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.01));
FunctionTest<ThreeHumpCamelFunction>(optimizer, 0.1, 0.01);
}
+14 -116
View File
@@ -22,28 +22,11 @@ using namespace ens::test;
*/
TEST_CASE("BBSBBLogisticRegressionTest", "[BigBatchSGDTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
for (size_t batchSize = 40; batchSize < 50; batchSize += 5)
// Run big-batch SGD with a couple of batch sizes.
for (size_t batchSize = 350; batchSize < 360; batchSize += 5)
{
BBS_Armijo bbsgd(batchSize, 0.005, 0.1, 10000, 1e-6, true, true);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
arma::mat coordinates = lr.GetInitialPoint();
bbsgd.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
BBS_BB bbsgd(batchSize, 0.001, 0.1, 10000, 1e-8, true, true);
LogisticRegressionFunctionTest(bbsgd, 0.003, 0.006, 3);
}
}
@@ -53,28 +36,11 @@ TEST_CASE("BBSBBLogisticRegressionTest", "[BigBatchSGDTest]")
*/
TEST_CASE("BBSArmijoLogisticRegressionTest", "[BigBatchSGDTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run big-batch SGD with a couple of batch sizes.
for (size_t batchSize = 40; batchSize < 50; batchSize += 1)
{
BBS_Armijo bbsgd(batchSize, 0.005, 0.1, 10000, 1e-6, true, true);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
arma::mat coordinates = lr.GetInitialPoint();
bbsgd.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(bbsgd, 0.003, 0.006, 3);
}
}
@@ -84,28 +50,11 @@ TEST_CASE("BBSArmijoLogisticRegressionTest", "[BigBatchSGDTest]")
*/
TEST_CASE("BBSBBLogisticRegressionFMatTest", "[BigBatchSGDTest]")
{
arma::fmat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run big-batch SGD with a couple of batch sizes.
for (size_t batchSize = 350; batchSize < 360; batchSize += 5)
{
BBS_BB bbsgd(batchSize, 0.001, 0.1, 10000, 1e-8, true, true);
LogisticRegression<arma::fmat> lr(shuffledData, shuffledResponses, 0.5);
arma::fmat coordinates = lr.GetInitialPoint();
bbsgd.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(bbsgd, 0.003, 0.006, 3);
}
}
@@ -115,28 +64,11 @@ TEST_CASE("BBSBBLogisticRegressionFMatTest", "[BigBatchSGDTest]")
*/
TEST_CASE("BBSArmijoLogisticRegressionFMatTest", "[BigBatchSGDTest]")
{
arma::fmat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run big-batch SGD with a couple of batch sizes.
for (size_t batchSize = 40; batchSize < 50; batchSize += 1)
{
BBS_Armijo bbsgd(batchSize, 0.01, 0.1, 10000, 1e-6, true, true);
LogisticRegression<arma::fmat> lr(shuffledData, shuffledResponses, 0.5);
arma::fmat coordinates = lr.GetInitialPoint();
bbsgd.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(bbsgd, 0.003, 0.006, 5);
}
}
@@ -149,28 +81,11 @@ TEST_CASE("BBSArmijoLogisticRegressionFMatTest", "[BigBatchSGDTest]")
*/
TEST_CASE("BBSBBLogisticRegressionSpMatTest", "[BigBatchSGDTest]")
{
arma::sp_mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run big-batch SGD with a couple of batch sizes.
for (size_t batchSize = 350; batchSize < 360; batchSize += 5)
{
BBS_BB bbsgd(batchSize, 0.005, 0.5, 10000, 1e-8, true, true);
LogisticRegression<arma::sp_mat> lr(shuffledData, shuffledResponses, 0.5);
arma::sp_mat coordinates = lr.GetInitialPoint();
bbsgd.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::sp_mat>(bbsgd, 0.003, 0.006, 3);
}
}
@@ -180,28 +95,11 @@ TEST_CASE("BBSBBLogisticRegressionSpMatTest", "[BigBatchSGDTest]")
*/
TEST_CASE("BBSArmijoLogisticRegressionSpMatTest", "[BigBatchSGDTest]")
{
arma::sp_mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run big-batch SGD with a couple of batch sizes.
for (size_t batchSize = 40; batchSize < 50; batchSize += 1)
{
BBS_Armijo bbsgd(batchSize, 0.01, 0.001, 10000, 1e-6, true, true);
LogisticRegression<arma::sp_mat> lr(shuffledData, shuffledResponses, 0.5);
arma::sp_mat coordinates = lr.GetInitialPoint();
bbsgd.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::sp_mat>(bbsgd, 0.003, 0.006, 3);
}
}
+31 -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);
}
/**
+5606 -1745
View File
File diff suppressed because it is too large Load Diff
+8 -124
View File
@@ -17,55 +17,14 @@
using namespace ens;
using namespace ens::test;
/**
* Tests the CMA-ES optimizer using a simple test function.
*/
TEST_CASE("SimpleTestFunction", "[CMAESTest]")
{
SGDTestFunction f;
CMAES<> optimizer(0, -1, 1, 32, 200, -1);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.003));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.003));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.003));
}
/**
* Run CMA-ES with the full selection policy on logistic regression and
* make sure the results are acceptable.
*/
TEST_CASE("CMAESLogisticRegressionTest", "[CMAESTest]")
{
const size_t trials = 3;
bool success = false;
for (size_t trial = 0; trial < trials; ++trial)
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
CMAES<> cmaes(0, -1, 1, 32, 200, 1e-3);
arma::mat coordinates = lr.GetInitialPoint();
cmaes.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
if (acc >= 99.7 && testAcc >= 99.4)
{
success = true;
break;
}
}
REQUIRE(success == true);
CMAES<> cmaes(0, -1, 1, 32, 200, 1e-3);
LogisticRegressionFunctionTest(cmaes, 0.003, 0.006, 5);
}
/**
@@ -74,33 +33,8 @@ TEST_CASE("CMAESLogisticRegressionTest", "[CMAESTest]")
*/
TEST_CASE("ApproxCMAESLogisticRegressionTest", "[CMAESTest]")
{
const size_t trials = 3;
bool success = false;
for (size_t trial = 0; trial < trials; ++trial)
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
ApproxCMAES<> cmaes(0, -1, 1, 32, 200, 1e-3);
arma::mat coordinates = lr.GetInitialPoint();
cmaes.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
if (acc >= 99.7 && testAcc >= 99.4)
{
success = true;
break;
}
}
REQUIRE(success == true);
ApproxCMAES<> cmaes(0, -1, 1, 32, 200, 1e-3);
LogisticRegressionFunctionTest(cmaes, 0.003, 0.006, 5);
}
/**
@@ -109,33 +43,8 @@ TEST_CASE("ApproxCMAESLogisticRegressionTest", "[CMAESTest]")
*/
TEST_CASE("CMAESLogisticRegressionFMatTest", "[CMAESTest]")
{
const size_t trials = 3;
bool success = false;
for (size_t trial = 0; trial < trials; ++trial)
{
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);
CMAES<> cmaes(0, -1, 1, 32, 200, 1e-3);
arma::fmat coordinates = lr.GetInitialPoint();
cmaes.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
if (acc >= 99.0 && testAcc >= 98.0)
{
success = true;
break;
}
}
REQUIRE(success == true);
CMAES<> cmaes(0, -1, 1, 32, 200, 1e-3);
LogisticRegressionFunctionTest<arma::fmat>(cmaes, 0.01, 0.02, 5);
}
/**
@@ -144,31 +53,6 @@ TEST_CASE("CMAESLogisticRegressionFMatTest", "[CMAESTest]")
*/
TEST_CASE("ApproxCMAESLogisticRegressionFMatTest", "[CMAESTest]")
{
const size_t trials = 3;
bool success = false;
for (size_t trial = 0; trial < trials; ++trial)
{
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);
ApproxCMAES<> cmaes(0, -1, 1, 32, 200, 1e-3);
arma::fmat coordinates = lr.GetInitialPoint();
cmaes.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
if (acc >= 99.0 && testAcc >= 98.0)
{
success = true;
break;
}
}
REQUIRE(success == true);
ApproxCMAES<> cmaes(0, -1, 1, 32, 200, 1e-3);
LogisticRegressionFunctionTest<arma::fmat>(cmaes, 0.01, 0.02, 5);
}
+28 -81
View File
@@ -10,7 +10,6 @@
* 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"
@@ -24,24 +23,8 @@ using namespace std;
*/
TEST_CASE("CNELogisticRegressionTest", "[CNETest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
CNE opt(300, 150, 0.2, 0.2, 0.2, -1);
arma::mat coordinates = lr.GetInitialPoint();
opt.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(opt, 0.003, 0.006);
}
/**
@@ -50,24 +33,8 @@ TEST_CASE("CNELogisticRegressionTest", "[CNETest]")
*/
TEST_CASE("CNELogisticRegressionFMatTest", "[CNETest]")
{
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);
CNE opt(300, 150, 0.2, 0.2, 0.2, -1);
arma::fmat coordinates = lr.GetInitialPoint();
opt.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(opt, 0.003, 0.006);
}
/**
@@ -90,14 +57,8 @@ TEST_CASE("CNECrossInTrayFunctionTest", "[CNETest]")
*/
TEST_CASE("CNEAckleyFunctionTest", "[CNETest]")
{
AckleyFunction f;
CNE optimizer(450, 1500, 0.3, 0.3, 0.3, -1);
arma::mat coordinates = arma::mat("3; 3");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0).margin(0.1));
FunctionTest<AckleyFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -105,14 +66,8 @@ TEST_CASE("CNEAckleyFunctionTest", "[CNETest]")
*/
TEST_CASE("CNEBealeFunctionTest", "[CNETest]")
{
BealeFunction f;
CNE optimizer(450, 1500, 0.3, 0.3, 0.3, -1);
arma::mat coordinates = arma::mat("3; 3");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(3).margin(0.1));
REQUIRE(coordinates(1) == Approx(0.5).margin(0.1));
FunctionTest<BealeFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -120,14 +75,8 @@ TEST_CASE("CNEBealeFunctionTest", "[CNETest]")
*/
TEST_CASE("CNEGoldsteinPriceFunctionTest", "[CNETest]")
{
GoldsteinPriceFunction f;
CNE optimizer(450, 1500, 0.3, 0.3, 0.1, -1);
arma::mat coordinates = arma::mat("0.5; -0.5");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.1));
REQUIRE(coordinates(1) == Approx(-1).margin(0.1));
FunctionTest<GoldsteinPriceFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -135,14 +84,8 @@ TEST_CASE("CNEGoldsteinPriceFunctionTest", "[CNETest]")
*/
TEST_CASE("CNELevyFunctionN13Test", "[CNETest]")
{
LevyFunctionN13 f;
CNE optimizer(450, 1500, 0.3, 0.3, 0.02, -1);
arma::mat coordinates = arma::mat("1.5; 0.5");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(1).margin(0.1));
REQUIRE(coordinates(1) == Approx(1).margin(0.1));
FunctionTest<LevyFunctionN13>(optimizer, 0.5, 0.1);
}
/**
@@ -165,14 +108,8 @@ TEST_CASE("CNEHimmelblauFunctionTest", "[CNETest]")
*/
TEST_CASE("CNEThreeHumpCamelFunctionTest", "[CNETest]")
{
ThreeHumpCamelFunction f;
CNE optimizer(450, 1500, 0.3, 0.3, 0.3, -1);
arma::mat coordinates = arma::mat("1; 1");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0).margin(0.1));
FunctionTest<ThreeHumpCamelFunction>(optimizer, 0.5, 0.1);
}
// TODO: The CNE optimizer with the given parameter occasionally fails to find a
@@ -186,11 +123,26 @@ TEST_CASE("CNESchafferFunctionN4Test", "[CNETest]")
SchafferFunctionN4 f;
CNE optimizer(500, 1600, 0.3, 0.3, 0.3, -1);
arma::mat coordinates = arma::mat("0.5; 2");
optimizer.Optimize(f, coordinates);
// We allow a few trials.
for (size_t trial = 0; trial < 5; ++trial)
{
arma::mat coordinates = arma::mat("0.5; 2");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.1));
REQUIRE(abs(coordinates(1)) == Approx(1.25313).margin(0.1));
if (trial != 4)
{
if (coordinates(0) != Approx(0).margin(0.1))
continue;
if (abs(coordinates(1)) != Approx(1.25313).margin(0.1))
continue;
}
REQUIRE(coordinates(0) == Approx(0).margin(0.1));
REQUIRE(abs(coordinates(1)) == Approx(1.25313).margin(0.1));
// The test was successfull or reached the maximum number of trials.
break;
}
}
/**
@@ -198,12 +150,7 @@ TEST_CASE("CNESchafferFunctionN4Test", "[CNETest]")
*/
TEST_CASE("CNESchafferFunctionN2Test", "[CNETest]")
{
SchafferFunctionN2 f;
// We allow a few trials in case convergence is not achieved.
CNE optimizer(500, 1600, 0.3, 0.3, 0.3, -1);
arma::mat coordinates = arma::mat("0.5; -0.5");
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0).margin(0.1));
FunctionTest<SchafferFunctionN2>(optimizer, 0.5, 0.1, 7);
}
+2 -34
View File
@@ -20,24 +20,8 @@ using namespace ens::test;
*/
TEST_CASE("DELogisticRegressionTest", "[DETest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
DE opt(200, 1000, 0.6, 0.8, 1e-5);
arma::mat coordinates = lr.GetInitialPoint();
opt.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(opt, 0.01, 0.02, 3);
}
/**
@@ -46,22 +30,6 @@ TEST_CASE("DELogisticRegressionTest", "[DETest]")
*/
TEST_CASE("DELogisticRegressionFMatTest", "[DETest]")
{
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);
DE opt(200, 1000, 0.6, 0.8, 1e-5);
arma::fmat coordinates = lr.GetInitialPoint();
opt.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const float acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.03)); // 3% error tolerance.
const float testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.06)); // 6% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(opt, 0.03, 0.06, 3);
}
+5 -61
View File
@@ -17,45 +17,13 @@
using namespace ens;
using namespace ens::test;
/**
* Test the Eve optimizer on the simple SGD function.
*/
TEST_CASE("EveSGDFunction","[EveTest]")
{
SGDTestFunction f;
Eve optimizer(1e-3, 1, 0.9, 0.999, 0.999, 1e-8, 10, 400000, 1e-9, true);
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));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.1));
}
/**
* Run Eve on logistic regression and make sure the results are acceptable.
*/
TEST_CASE("EveLogisticRegressionTest","[EveTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
Eve optimizer(1e-3, 1, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true);
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
@@ -63,14 +31,8 @@ TEST_CASE("EveLogisticRegressionTest","[EveTest]")
*/
TEST_CASE("EveSphereFunctionTest","[EveTest]")
{
SphereFunction f(2);
Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true);
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));
FunctionTest<SphereFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -78,14 +40,8 @@ TEST_CASE("EveSphereFunctionTest","[EveTest]")
*/
TEST_CASE("EveStyblinskiTangFunctionTest","[EveTest]")
{
StyblinskiTangFunction f(2);
Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(-2.9).epsilon(0.01));
REQUIRE(coordinates(1) == Approx(-2.9).epsilon(0.01));
FunctionTest<StyblinskiTangFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -94,14 +50,8 @@ TEST_CASE("EveStyblinskiTangFunctionTest","[EveTest]")
*/
TEST_CASE("EveStyblinskiTangFunctionFMatTest","[EveTest]")
{
StyblinskiTangFunction f(2);
Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(-2.9).epsilon(0.01));
REQUIRE(coordinates(1) == Approx(-2.9).epsilon(0.01));
FunctionTest<StyblinskiTangFunction, arma::fmat>(optimizer, 0.5, 0.1);
}
#if ARMA_VERSION_MAJOR > 9 ||\
@@ -113,14 +63,8 @@ TEST_CASE("EveStyblinskiTangFunctionFMatTest","[EveTest]")
*/
TEST_CASE("EveStyblinskiTangFunctionSpMatTest","[EveTest]")
{
StyblinskiTangFunction f(2);
Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true);
arma::sp_mat coordinates = f.GetInitialPoint<arma::sp_mat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(-2.9).epsilon(0.01));
REQUIRE(coordinates(1) == Approx(-2.9).epsilon(0.01));
FunctionTest<StyblinskiTangFunction, arma::sp_mat>(optimizer, 0.5, 0.1);
}
#endif
+4 -53
View File
@@ -17,45 +17,13 @@
using namespace ens;
using namespace ens::test;
/**
* Test the FTML optimizer on the simple SGD function.
*/
TEST_CASE("FTMLSGDFunction", "[FTMLTest]")
{
SGDTestFunction f;
FTML optimizer(0.005, 1, 0.9, 0.999, 1e-8, 1000000, 1e-9, true);
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));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.1));
}
/**
* Run FTML on logistic regression and make sure the results are acceptable.
*/
TEST_CASE("FTMLLogisticRegressionTest", "[FTMLTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
FTML optimizer(0.001, 1, 0.9, 0.999, 1e-8, 100000, 1e-5, true);
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
@@ -63,13 +31,8 @@ TEST_CASE("FTMLLogisticRegressionTest", "[FTMLTest]")
*/
TEST_CASE("FTMLSphereFunctionTest", "[FTMLTest]")
{
SphereFunction f(2);
FTML optimizer(0.001, 2, 0.9, 0.999, 1e-8, 500000, 1e-9, true);
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));
FunctionTest<SphereFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -77,14 +40,8 @@ TEST_CASE("FTMLSphereFunctionTest", "[FTMLTest]")
*/
TEST_CASE("FTMLStyblinskiTangFunctionTest", "[FTMLTest]")
{
StyblinskiTangFunction f(2);
FTML optimizer(0.001, 2, 0.9, 0.999, 1e-8, 100000, 1e-5, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(-2.9).epsilon(0.01));
REQUIRE(coordinates(1) == Approx(-2.9).epsilon(0.01));
FunctionTest<StyblinskiTangFunction>(optimizer, 0.5, 0.1);
}
/**
@@ -93,14 +50,8 @@ TEST_CASE("FTMLStyblinskiTangFunctionTest", "[FTMLTest]")
*/
TEST_CASE("FTMLStyblinskiTangFunctionFMatTest", "[FTMLTest]")
{
StyblinskiTangFunction f(2);
FTML optimizer(0.001, 2, 0.9, 0.999, 1e-8, 100000, 1e-5, true);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(-2.9).epsilon(0.01));
REQUIRE(coordinates(1) == Approx(-2.9).epsilon(0.01));
FunctionTest<StyblinskiTangFunction, arma::fmat>(optimizer, 0.5, 0.1);
}
// A test with sp_mat is not done, because FTML uses some parts internally that
+4 -29
View File
@@ -12,50 +12,25 @@
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
TEST_CASE("SimpleGDTestFunction", "[GradientDescentTest]")
{
GDTestFunction f;
GradientDescent s(0.01, 5000000, 1e-9);
arma::mat coordinates = f.GetInitialPoint<arma::mat>();
double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0.0).margin(1e-4));
REQUIRE(coordinates(0) == Approx(0.0).margin(1e-2));
REQUIRE(coordinates(1) == Approx(0.0).margin(1e-2));
REQUIRE(coordinates(2) == Approx(0.0).margin(1e-2));
FunctionTest<GDTestFunction>(s, 0.1, 0.01);
}
TEST_CASE("GDRosenbrockTest", "[GradientDescentTest]")
{
// Create the Rosenbrock function.
RosenbrockFunction f;
GradientDescent s(0.001, 0, 1e-15);
arma::mat coordinates = f.GetInitialPoint<arma::mat>();
double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0.0).margin(1e-10));
for (size_t j = 0; j < 2; ++j)
REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-5));
FunctionTest<RosenbrockFunction>(s, 0.01, 0.001);
}
TEST_CASE("GDRosenbrockFMatTest", "[GradientDescentTest]")
{
// Create the Rosenbrock function.
RosenbrockFunction f;
GradientDescent s(0.001, 0, 1e-15);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
float result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0.0).margin(1e-5));
for (size_t j = 0; j < 2; ++j)
REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-3));
FunctionTest<RosenbrockFunction, arma::fmat>(s, 0.1, 0.01);
}
+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));
}
+4 -40
View File
@@ -22,29 +22,11 @@ using namespace ens::test;
*/
TEST_CASE("IQNLogisticRegressionTest", "[IQNTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
// Now run SGDR with snapshot ensembles on a couple of batch sizes.
// Run on a couple of batch sizes.
for (size_t batchSize = 1; batchSize < 9; batchSize += 4)
{
IQN iqn(0.01, batchSize, 5000, 0.01);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
arma::mat coordinates = lr.GetInitialPoint();
iqn.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.013)); // 1.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.016)); // 1.6% error tolerance.
LogisticRegressionFunctionTest(iqn, 0.013, 0.016);
}
}
@@ -54,28 +36,10 @@ TEST_CASE("IQNLogisticRegressionTest", "[IQNTest]")
*/
TEST_CASE("IQNLogisticRegressionFMatTest", "[IQNTest]")
{
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);
// Now run SGDR with snapshot ensembles on a couple of batch sizes.
// Run on a couple of batch sizes.
for (size_t batchSize = 1; batchSize < 9; batchSize += 4)
{
IQN iqn(0.001, batchSize, 5000, 0.01);
LogisticRegression<arma::fmat> lr(shuffledData, shuffledResponses, 0.5);
arma::fmat coordinates = lr.GetInitialPoint();
iqn.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.013)); // 1.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.016)); // 1.6% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(iqn, 0.013, 0.016);
}
}
+12 -114
View File
@@ -21,28 +21,11 @@ using namespace ens::test;
*/
TEST_CASE("KatyushaLogisticRegressionTest", "[KatyushaTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run with a couple of batch sizes.
for (size_t batchSize = 30; batchSize < 45; batchSize += 5)
{
Katyusha optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.015, 0.015);
}
}
@@ -52,28 +35,11 @@ TEST_CASE("KatyushaLogisticRegressionTest", "[KatyushaTest]")
*/
TEST_CASE("KatyushaProximalLogisticRegressionTest", "[KatyushaTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run with a couple of batch sizes.
for (size_t batchSize = 30; batchSize < 45; batchSize += 5)
{
KatyushaProximal optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.015, 0.015);
}
}
@@ -83,28 +49,11 @@ TEST_CASE("KatyushaProximalLogisticRegressionTest", "[KatyushaTest]")
*/
TEST_CASE("KatyushaLogisticRegressionFMatTest", "[KatyushaTest]")
{
arma::fmat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run with a couple of batch sizes.
for (size_t batchSize = 30; batchSize < 45; batchSize += 5)
{
Katyusha optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true);
LogisticRegression<arma::fmat> lr(shuffledData, shuffledResponses, 0.5);
arma::fmat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.015, 0.015);
}
}
@@ -114,28 +63,11 @@ TEST_CASE("KatyushaLogisticRegressionFMatTest", "[KatyushaTest]")
*/
TEST_CASE("KatyushaProximalLogisticRegressionFMatTest", "[KatyushaTest]")
{
arma::fmat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run with a couple of batch sizes.
for (size_t batchSize = 30; batchSize < 45; batchSize += 5)
{
KatyushaProximal optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true);
LogisticRegression<arma::fmat> lr(shuffledData, shuffledResponses, 0.5);
arma::fmat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.015, 0.015);
}
}
@@ -148,28 +80,11 @@ TEST_CASE("KatyushaProximalLogisticRegressionFMatTest", "[KatyushaTest]")
*/
TEST_CASE("KatyushaLogisticRegressionSpMatTest", "[KatyushaTest]")
{
arma::sp_mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run with a couple of batch sizes.
for (size_t batchSize = 30; batchSize < 45; batchSize += 5)
{
Katyusha optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true);
LogisticRegression<arma::sp_mat> lr(shuffledData, shuffledResponses, 0.5);
arma::sp_mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest<arma::sp_mat>(optimizer, 0.015, 0.015);
}
}
@@ -179,28 +94,11 @@ TEST_CASE("KatyushaLogisticRegressionSpMatTest", "[KatyushaTest]")
*/
TEST_CASE("KatyushaProximalLogisticRegressionSpMatTest", "[KatyushaTest]")
{
arma::sp_mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run big-batch SGD with a couple of batch sizes.
// Run with a couple of batch sizes.
for (size_t batchSize = 30; batchSize < 45; batchSize += 5)
{
KatyushaProximal optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true);
LogisticRegression<arma::sp_mat> lr(shuffledData, shuffledResponses, 0.5);
arma::sp_mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest<arma::sp_mat>(optimizer, 0.015, 0.015);
}
}
+7 -62
View File
@@ -12,6 +12,7 @@
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
@@ -21,18 +22,9 @@ using namespace ens::test;
*/
TEST_CASE("RosenbrockFunctionTest", "[LBFGSTest]")
{
RosenbrockFunction f;
L_BFGS lbfgs;
lbfgs.MaxIterations() = 10000;
arma::mat coords = f.GetInitialPoint();
lbfgs.Optimize(f, coords);
double finalValue = f.Evaluate(coords);
REQUIRE(finalValue == Approx(0.0).margin(1e-5));
REQUIRE(coords(0) == Approx(1.0).epsilon(1e-7));
REQUIRE(coords(1) == Approx(1.0).epsilon(1e-7));
FunctionTest<RosenbrockFunction>(lbfgs, 0.01, 0.001);
}
/**
@@ -40,18 +32,9 @@ TEST_CASE("RosenbrockFunctionTest", "[LBFGSTest]")
*/
TEST_CASE("RosenbrockFunctionFloatTest", "[LBFGSTest]")
{
RosenbrockFunction f;
L_BFGS lbfgs;
lbfgs.MaxIterations() = 10000;
arma::fmat coords = f.GetInitialPoint<arma::fvec>();
lbfgs.Optimize(f, coords);
float finalValue = f.Evaluate(coords);
REQUIRE(finalValue == Approx(0.0f).margin(1e-3));
REQUIRE(coords(0) == Approx(1.0f).epsilon(1e-4));
REQUIRE(coords(1) == Approx(1.0f).epsilon(1e-4));
FunctionTest<RosenbrockFunction, arma::fmat>(lbfgs, 0.1, 0.01);
}
/**
@@ -79,18 +62,9 @@ TEST_CASE("RosenbrockFunctionSpGradTest", "[LBFGSTest]")
*/
TEST_CASE("RosenbrockFunctionSpMatTest", "[LBFGSTest]")
{
RosenbrockFunction f;
L_BFGS lbfgs;
lbfgs.MaxIterations() = 10000;
arma::sp_mat coords = f.GetInitialPoint<arma::sp_vec>();
lbfgs.Optimize(f, coords);
double finalValue = f.Evaluate(coords);
REQUIRE(finalValue == Approx(0.0).margin(1e-5));
REQUIRE(coords(0) == Approx(1.0).epsilon(1e-7));
REQUIRE(coords(1) == Approx(1.0).epsilon(1e-7));
FunctionTest<RosenbrockFunction, arma::sp_mat>(lbfgs, 0.01, 0.001);
}
/**
@@ -98,15 +72,9 @@ TEST_CASE("RosenbrockFunctionSpMatTest", "[LBFGSTest]")
*/
TEST_CASE("ColvilleFunctionTest", "[LBFGSTest]")
{
ColvilleFunction f;
L_BFGS lbfgs;
lbfgs.MaxIterations() = 10000;
arma::vec coords = f.GetInitialPoint();
lbfgs.Optimize(f, coords);
REQUIRE(coords(0) == Approx(1.0).epsilon(1e-7));
REQUIRE(coords(1) == Approx(1.0).epsilon(1e-7));
FunctionTest<ColvilleFunction>(lbfgs, 0.01, 0.001);
}
/**
@@ -114,20 +82,9 @@ TEST_CASE("ColvilleFunctionTest", "[LBFGSTest]")
*/
TEST_CASE("WoodFunctionTest", "[LBFGSTest]")
{
WoodFunction f;
L_BFGS lbfgs;
lbfgs.MaxIterations() = 10000;
arma::vec coords = f.GetInitialPoint();
lbfgs.Optimize(f, coords);
double finalValue = f.Evaluate(coords);
REQUIRE(finalValue == Approx(0.0).margin(1e-5));
REQUIRE(coords(0) == Approx(1.0).epsilon(1e-7));
REQUIRE(coords(1) == Approx(1.0).epsilon(1e-7));
REQUIRE(coords(2) == Approx(1.0).epsilon(1e-7));
REQUIRE(coords(3) == Approx(1.0).epsilon(1e-7));
FunctionTest<WoodFunction>(lbfgs, 0.01, 0.001);
}
/**
@@ -164,19 +121,7 @@ TEST_CASE("GeneralizedRosenbrockFunctionTest", "[LBFGSTest]")
*/
TEST_CASE("RosenbrockWoodFunctionTest", "[LBFGSTest]")
{
RosenbrockWoodFunction f;
L_BFGS lbfgs;
lbfgs.MaxIterations() = 10000;
arma::mat coords = f.GetInitialPoint();
lbfgs.Optimize(f, coords);
double finalValue = f.Evaluate(coords);
REQUIRE(finalValue == Approx(0.0).margin(1e-5));
for (int row = 0; row < 4; row++)
{
REQUIRE((coords(row, 0)) == Approx(1.0).epsilon(1e-7));
REQUIRE((coords(row, 1)) == Approx(1.0).epsilon(1e-7));
}
FunctionTest<RosenbrockWoodFunction>(lbfgs, 0.01, 0.001);
}
+7 -64
View File
@@ -20,38 +20,13 @@ using namespace ens::test;
*/
TEST_CASE("LookaheadAdamSphereFunctionTest", "[LookaheadTest]")
{
SphereFunction f(2);
Lookahead<> optimizer(0.5, 5, 100000, 1e-5, NoDecay(), false, true);
optimizer.BaseOptimizer().StepSize() = 0.1;
optimizer.BaseOptimizer().BatchSize() = 2;
optimizer.BaseOptimizer().Beta1() = 0.7;
optimizer.BaseOptimizer().Tolerance() = 1e-15;
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 Lookahead - Adam optimizer on the SGDTest function.
*/
TEST_CASE("LookaheadAdamSimpleSGDTestFunction", "[LookaheadTest]")
{
SGDTestFunction f;
Adam adam(0.001, 1, 0.9, 0.999, 1e-8, 5, 1e-19, false, true);
Lookahead<Adam> optimizer(adam, 0.5, 5, 100000, 1e-15, NoDecay(),
false, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(1e-3));
REQUIRE(coordinates(1) == Approx(0.0).margin(1e-3));
REQUIRE(coordinates(2) == Approx(0.0).margin(1e-3));
// We allow a few trials.
FunctionTest<SphereFunction>(optimizer, 0.5, 0.2, 3);
}
/**
@@ -59,17 +34,10 @@ TEST_CASE("LookaheadAdamSimpleSGDTestFunction", "[LookaheadTest]")
*/
TEST_CASE("LookaheadAdaGradSphereFunction", "[LookaheadTest]")
{
SphereFunction f(2);
AdaGrad adagrad(0.99, 1, 1e-8, 5, 1e-15, true);
Lookahead<AdaGrad> optimizer(adagrad, 0.5, 5, 5000000, 1e-15, NoDecay(),
false, true);
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));
FunctionTest<SphereFunction>(optimizer, 0.5, 0.2, 3);
}
/**
@@ -78,44 +46,19 @@ TEST_CASE("LookaheadAdaGradSphereFunction", "[LookaheadTest]")
*/
TEST_CASE("LookaheadAdamLogisticRegressionTest","[LookaheadTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
Adam adam(0.001, 32, 0.9, 0.999, 1e-8, 5, 1e-19);
Lookahead<Adam> optimizer(adam, 0.5, 20, 100000, 1e-15, NoDecay(),
false, true);
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
* Test the Lookahead - Adam optimizer on the SGDTest function (float).
* Test the Lookahead - Adam optimizer on the Sphere function (float).
*/
TEST_CASE("LookaheadAdamSimpleSGDTestFunctionFloat", "[LookaheadTest]")
TEST_CASE("LookaheadAdamSimpleSphereFunctionFloat", "[LookaheadTest]")
{
SGDTestFunction f;
Adam adam(0.001, 1, 0.9, 0.999, 1e-8, 5, 1e-19, false, true);
Lookahead<Adam> optimizer(adam, 0.5, 5, 100000, 1e-15, NoDecay(),
false, true);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(1e-3));
REQUIRE(coordinates(1) == Approx(0.0).margin(1e-3));
REQUIRE(coordinates(2) == Approx(0.0).margin(1e-3));
FunctionTest<SphereFunction, arma::fmat>(optimizer, 0.5, 0.2, 3);
}
+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();
}
+618
View File
@@ -0,0 +1,618 @@
/**
* @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 < 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 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.
*/
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;
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));
}
/**
* 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));
}
+6 -6
View File
@@ -29,7 +29,7 @@ TEST_CASE("NesterovMomentumSGDSpeedUpTestFunction", "[NesterovMomentumSGDTest]")
arma::mat coordinates = f.GetInitialPoint();
double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(-1.0).epsilon(0.0025));
REQUIRE(result == Approx(-1.0).margin(0.01));
REQUIRE(coordinates(0) == Approx(0.0).margin(3e-3));
REQUIRE(coordinates(1) == Approx(0.0).margin(1e-6));
REQUIRE(coordinates(2) == Approx(0.0).margin(1e-6));
@@ -54,7 +54,7 @@ TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockTest", "[NesterovMomentumSGDT
REQUIRE(result == Approx(0.0).margin(1e-4));
for (size_t j = 0; j < i; ++j)
REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-5));
REQUIRE(coordinates(j) == Approx(1.0).epsilon(0.003));
}
}
@@ -76,15 +76,15 @@ TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockFMatTest",
size_t trial = 0;
float result = std::numeric_limits<float>::max();
arma::fmat coordinates;
while (trial++ < 5 && result > 0.1)
while (trial++ < 8 && result > 0.1)
{
coordinates = f.GetInitialPoint<arma::fmat>();
result = s.Optimize(f, coordinates);
}
REQUIRE(result == Approx(0.0).margin(1e-2));
REQUIRE(result == Approx(0.0).margin(0.02));
for (size_t j = 0; j < i; ++j)
REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-2));
REQUIRE(coordinates(j) == Approx(1.0).margin(0.05));
}
}
@@ -108,6 +108,6 @@ TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockSpMatTest",
REQUIRE(result == Approx(0.0).margin(1e-4));
for (size_t j = 0; j < i; ++j)
REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-5));
REQUIRE(coordinates(j) == Approx(1.0).epsilon(0.003));
}
}
+344 -48
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,88 +23,120 @@ 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;
arma::mat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
std::vector<arma::mat> bestFront = opt.Front();
bool allInRange = true;
for (arma::mat solution: bestFront)
// We allow a few trials in case of poor convergence.
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
double val = arma::as_scalar(solution);
arma::mat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
if (val < 0.0 || val > 2.0)
opt.Optimize(objectives, coords);
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
allInRange = false;
double val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<double>(val, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
}
}
if (allInRange)
{
success = true;
break;
}
}
REQUIRE(allInRange);
REQUIRE(success == true);
}
/**
* 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;
arma::mat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
std::vector<arma::mat> bestFront = opt.Front();
bool allInRange = true;
for (arma::mat solution: bestFront)
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
double val = arma::as_scalar(solution);
arma::mat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
if (val < 0.0 || val > 2.0)
opt.Optimize(objectives, coords);
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
allInRange = false;
double val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<double>(val, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
}
}
if (allInRange)
{
success = true;
break;
}
}
REQUIRE(allInRange);
REQUIRE(success == true);
}
/**
* 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;
@@ -113,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;
@@ -122,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};
@@ -157,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;
@@ -166,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]);
}
}
+2 -15
View File
@@ -30,8 +30,6 @@ using namespace ens::test;
*/
TEST_CASE("SimpleParallelSGDTest", "[ParallelSGDTest]")
{
SparseTestFunction f;
ConstantStep decayPolicy(0.4);
// The batch size for this test should be chosen according to the threads
@@ -40,6 +38,7 @@ TEST_CASE("SimpleParallelSGDTest", "[ParallelSGDTest]")
size_t threadsAvailable = omp_get_max_threads();
SparseTestFunction f;
for (size_t i = threadsAvailable; i > 0; --i)
{
omp_set_num_threads(i);
@@ -47,19 +46,7 @@ TEST_CASE("SimpleParallelSGDTest", "[ParallelSGDTest]")
size_t batchSize = std::ceil((float) f.NumFunctions() / i);
ParallelSGD<ConstantStep> s(10000, batchSize, 1e-5, true, decayPolicy);
arma::mat coordinates = f.GetInitialPoint<arma::mat>();
double result = s.Optimize(f, coordinates);
// The final value of the objective function should be close to the optimal
// value, that is the sum of values at the vertices of the parabolas.
REQUIRE(result == Approx(123.75).epsilon(0.0001));
// The co-ordinates should be the vertices of the parabolas.
REQUIRE(coordinates(0) == Approx(2.0).epsilon(0.0002));
REQUIRE(coordinates(1) == Approx(1.0).epsilon(0.0002));
REQUIRE(coordinates(2) == Approx(1.5).epsilon(0.0002));
REQUIRE(coordinates(3) == Approx(4.0).epsilon(0.0002));
FunctionTest<SparseTestFunction>(s, 0.01, 0.001);
}
}
+99 -29
View File
@@ -66,14 +66,28 @@ TEST_CASE("LBestPSORosenbrockTest","[PSOTest]")
lowerBound.fill(50);
upperBound.fill(60);
LBestPSO s(250, lowerBound, upperBound, 3000, 600, 1e-30, 2.05, 2.05);
arma::vec coordinates = f.GetInitialPoint();
// We allow a few trials.
for (size_t trial = 0; trial < 3; ++trial)
{
LBestPSO s(250, lowerBound, upperBound, 3000, 600, 1e-30, 2.05, 2.05);
arma::vec coordinates = f.GetInitialPoint();
const double result = s.Optimize(f, coordinates);
const double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0.0).margin(1e-3));
REQUIRE(coordinates(0) == Approx(1.0).epsilon(1e-2));
REQUIRE(coordinates(1) == Approx(1.0).epsilon(1e-2));
if (trial != 2)
{
if (result != Approx(0.0).margin(0.03))
continue;
if (coordinates(0) != Approx(1.0).margin(0.02))
continue;
if (coordinates(1) != Approx(1.0).margin(0.02))
continue;
}
REQUIRE(result == Approx(0.0).margin(0.03));
REQUIRE(coordinates(0) == Approx(1.0).margin(0.02));
REQUIRE(coordinates(1) == Approx(1.0).margin(0.02));
}
}
/**
@@ -89,14 +103,28 @@ TEST_CASE("LBestPSORosenbrockFMatTest","[PSOTest]")
lowerBound.fill(50);
upperBound.fill(60);
LBestPSO s(250, lowerBound, upperBound, 5000, 600, 1e-30, 2.05, 2.05);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
// We allow a few trials.
for (size_t trial = 0; trial < 5; ++trial)
{
LBestPSO s(250, lowerBound, upperBound, 5000, 600, 1e-30, 2.05, 2.05);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
const double result = s.Optimize(f, coordinates);
const double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0.0).margin(1e-3));
REQUIRE(coordinates(0) == Approx(1.0).epsilon(1e-2));
REQUIRE(coordinates(1) == Approx(1.0).epsilon(1e-2));
if (trial != 4)
{
if (result != Approx(0.0).margin(0.03))
continue;
if (coordinates(0) != Approx(1.0).margin(0.03))
continue;
if (coordinates(1) != Approx(1.0).margin(0.03))
continue;
}
REQUIRE(result == Approx(0.0).margin(0.03));
REQUIRE(coordinates(0) == Approx(1.0).margin(0.03));
REQUIRE(coordinates(1) == Approx(1.0).margin(0.03));
}
}
/**
@@ -111,14 +139,28 @@ TEST_CASE("LBestPSORosenbrockDoubleTest","[PSOTest]")
double lowerBound = 50;
double upperBound = 60;
LBestPSO s(250, lowerBound, upperBound, 5000, 400, 1e-30, 2.05, 2.05);
arma::vec coordinates = f.GetInitialPoint();
// We allow a few trials.
for (size_t trial = 0; trial < 3; ++trial)
{
LBestPSO s(250, lowerBound, upperBound, 5000, 400, 1e-30, 2.05, 2.05);
arma::vec coordinates = f.GetInitialPoint();
const double result = s.Optimize(f, coordinates);
const double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(0.0).margin(1e-3));
REQUIRE(coordinates(0) == Approx(1.0).epsilon(1e-3));
REQUIRE(coordinates(1) == Approx(1.0).epsilon(1e-3));
if (trial != 2)
{
if (result != Approx(0.0).margin(1e-3))
continue;
if (coordinates(0) != Approx(1.0).epsilon(1e-2))
continue;
if (coordinates(1) != Approx(1.0).epsilon(1e-2))
continue;
}
REQUIRE(result == Approx(0.0).margin(0.005));
REQUIRE(coordinates(0) == Approx(1.0).margin(0.005));
REQUIRE(coordinates(1) == Approx(1.0).margin(0.005));
}
}
/**
@@ -134,13 +176,29 @@ TEST_CASE("LBestPSOCrossInTrayFunctionTest", "[PSOTest]")
lowerBound.fill(-1);
upperBound.fill(1);
LBestPSO s(500, lowerBound, upperBound, 6000, 400, 1e-30, 2.05, 2.05);
arma::mat coordinates = arma::mat("10; 10");
const double result = s.Optimize(f, coordinates);
// We allow many trials---sometimes this can have trouble converging.
for (size_t trial = 0; trial < 15; ++trial)
{
LBestPSO s(500, lowerBound, upperBound, 6000, 400, 1e-30, 2.05, 2.05);
arma::mat coordinates = arma::mat("10; 10");
const double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(-2.06261).margin(0.01));
REQUIRE(abs(coordinates(0)) == Approx(1.34941).margin(0.01));
REQUIRE(abs(coordinates(1)) == Approx(1.34941).margin(0.01));
if (trial != 14)
{
if (std::isinf(result) || std::isnan(result))
continue;
if (result != Approx(-2.06261).margin(0.01))
continue;
if (abs(coordinates(0)) != Approx(1.34941).margin(0.01))
continue;
if (abs(coordinates(1)) != Approx(1.34941).margin(0.01))
continue;
}
REQUIRE(result == Approx(-2.06261).margin(0.01));
REQUIRE(abs(coordinates(0)) == Approx(1.34941).margin(0.01));
REQUIRE(abs(coordinates(1)) == Approx(1.34941).margin(0.01));
}
}
/**
@@ -201,13 +259,25 @@ TEST_CASE("LBestPSOGoldsteinPriceFunctionTest", "[PSOTest]")
lowerBound.fill(1.6);
upperBound.fill(2);
LBestPSO s(64, lowerBound, upperBound);
// Allow a few trials in case of failure.
for (size_t trial = 0; trial < 10; ++trial)
{
LBestPSO s(64, lowerBound, upperBound);
arma::mat coordinates = arma::mat("1; 0");
s.Optimize(f, coordinates);
arma::mat coordinates = arma::mat("1; 0");
s.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0).margin(0.01));
REQUIRE(coordinates(1) == Approx(-1).margin(0.01));
if (trial != 9)
{
if (coordinates(0) != Approx(0).margin(0.01))
continue;
if (coordinates(1) != Approx(-1).margin(0.01))
continue;
}
REQUIRE(coordinates(0) == Approx(0).margin(0.01));
REQUIRE(coordinates(1) == Approx(-1).margin(0.01));
}
}
/**
+7 -30
View File
@@ -9,6 +9,7 @@
*/
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
@@ -16,56 +17,32 @@ using namespace ens::test;
/**
* Tests the Quasi Hyperbolic Momentum SGD update policy.
*/
TEST_CASE("QHSGDTestFunction", "[QHMomentumSGDTest]")
TEST_CASE("QHSphereFunction", "[QHMomentumSGDTest]")
{
SGDTestFunction f;
QHUpdate update(0.4, 0.9);
QHSGD s(0.0025, 1, 500000, 1e-10, true, update, NoDecay(), true, true);
arma::mat coordinates = f.GetInitialPoint();
double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(-1.0).epsilon(0.0025));
REQUIRE(coordinates(0) == Approx(0.0).margin(3e-3));
REQUIRE(coordinates(1) == Approx(0.0).margin(1e-6));
REQUIRE(coordinates(2) == Approx(0.0).margin(1e-6));
FunctionTest<SphereFunction>(s, 0.03, 0.003);
}
/**
* Tests the Quasi Hyperbolic Momentum SGD update policy using arma::fmat.
*/
TEST_CASE("QHSGDFMatTestFunction", "[QHMomentumSGDTest]")
TEST_CASE("QHSphereFunctionFMat", "[QHMomentumSGDTest]")
{
SGDTestFunction f;
QHUpdate update(0.9, 0.9);
QHSGD s(0.002, 1, 2500000, 1e-9, true, update);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
float result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(-1.0).epsilon(0.025));
REQUIRE(coordinates(0) == Approx(0.0).margin(3e-2));
REQUIRE(coordinates(1) == Approx(0.0).margin(1e-4));
REQUIRE(coordinates(2) == Approx(0.0).margin(1e-4));
FunctionTest<SphereFunction, arma::fmat>(s, 0.3, 0.03);
}
/**
* Tests the Quasi Hyperbolic Momentum SGD update policy using arma::sp_mat.
*/
TEST_CASE("QHSGDSpMatTestFunction", "[QHMomentumSGDTest]")
TEST_CASE("QHSpMatTestSphereFunction", "[QHMomentumSGDTest]")
{
SGDTestFunction f;
QHUpdate update(0.9, 0.9);
QHSGD s(0.002, 1, 2500000, 1e-15, true, update);
s.ExactObjective() = true;
arma::sp_mat coordinates = f.GetInitialPoint<arma::sp_mat>();
double result = s.Optimize(f, coordinates);
REQUIRE(result == Approx(-1.0).epsilon(0.0025));
REQUIRE(coordinates(0) == Approx(0.0).margin(3e-3));
REQUIRE(coordinates(1) == Approx(0.0).margin(1e-6));
REQUIRE(coordinates(2) == Approx(0.0).margin(1e-6));
FunctionTest<SphereFunction, arma::sp_mat>(s, 0.03, 0.003);
}
/**
+3 -64
View File
@@ -16,42 +16,13 @@
using namespace ens;
using namespace ens::test;
TEST_CASE("RMSPropSGDFunction", "[rmsprop]")
{
SGDTestFunction f;
RMSProp optimizer(1e-3, 1, 0.99, 1e-8, 5000000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(std::abs(coordinates(0)) <= 0.1);
REQUIRE(std::abs(coordinates(1)) <= 0.1);
REQUIRE(std::abs(coordinates(2)) <= 0.1);
}
/**
* Run RMSProp on logistic regression and make sure the results are acceptable.
*/
TEST_CASE("RMSPropLogisticRegressionTest", "[rmsprop]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
RMSProp optimizer;
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
@@ -60,24 +31,8 @@ TEST_CASE("RMSPropLogisticRegressionTest", "[rmsprop]")
*/
TEST_CASE("RMSPropLogisticRegressionFMatTest", "[rmsprop]")
{
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);
RMSProp optimizer;
arma::fmat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.003, 0.006);
}
#if ARMA_VERSION_MAJOR > 9 ||\
@@ -89,24 +44,8 @@ TEST_CASE("RMSPropLogisticRegressionFMatTest", "[rmsprop]")
*/
TEST_CASE("RMSPropLogisticRegressionSpMatTest", "[rmsprop]")
{
arma::sp_mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<arma::sp_mat> lr(shuffledData, shuffledResponses, 0.5);
RMSProp optimizer;
arma::sp_mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance.
LogisticRegressionFunctionTest<arma::sp_mat>(optimizer, 0.003, 0.006);
}
#endif
+8 -39
View File
@@ -12,6 +12,7 @@
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
@@ -47,33 +48,19 @@ TEST_CASE("SAGeneralizedRosenbrockTest","[SATest]")
// The Rosenbrock function is a simple function to optimize.
TEST_CASE("SARosenbrockTest", "[SATest]")
{
RosenbrockFunction f;
ExponentialSchedule schedule;
// The convergence is very sensitive to the choices of maxMove and initMove.
SA<> sa(schedule, 1000000, 1000., 1000, 100, 1e-11, 3, 1.5, 0.3, 0.3);
arma::mat coordinates = f.GetInitialPoint();
const double result = sa.Optimize(f, coordinates);
REQUIRE(result == Approx(0.0).margin(1e-5));
REQUIRE(coordinates(0) == Approx(1.0).epsilon(1e-4));
REQUIRE(coordinates(1) == Approx(1.0).epsilon(1e-4));
FunctionTest<RosenbrockFunction>(sa, 0.01, 0.001);
}
// The Rosenbrock function is a simple function to optimize. Use arma::fmat.
TEST_CASE("SARosenbrockFMatTest", "[SATest]")
{
RosenbrockFunction f;
ExponentialSchedule schedule;
// The convergence is very sensitive to the choices of maxMove and initMove.
SA<> sa(schedule, 1000000, 1000., 1000, 100, 1e-11, 3, 1.5, 0.3, 0.3);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
const float result = sa.Optimize(f, coordinates);
REQUIRE(result == Approx(0.0).margin(1e-3));
REQUIRE(coordinates(0) == Approx(1.0).epsilon(1e-2));
REQUIRE(coordinates(1) == Approx(1.0).epsilon(1e-2));
FunctionTest<RosenbrockFunction, arma::fmat>(sa, 0.1, 0.01);
}
/**
@@ -85,27 +72,9 @@ TEST_CASE("RastrigrinFunctionTest", "[SATest]")
// Simulated annealing isn't guaranteed to converge (except in very specific
// situations). If this works 1 of 4 times, I'm fine with that. All I want
// to know is that this implementation will escape from local minima.
size_t successes = 0;
for (size_t trial = 0; trial < 4; ++trial)
{
RastriginFunction f(2);
ExponentialSchedule schedule;
// The convergence is very sensitive to the choices of maxMove and initMove.
// SA<> sa(schedule, 2000000, 100, 50, 1000, 1e-12, 2, 2.0, 0.5, 0.1);
SA<> sa(schedule, 2000000, 100, 50, 1000, 1e-12, 2, 2.0, 0.5, 0.1);
arma::mat coordinates = f.GetInitialPoint();
const double result = sa.Optimize(f, coordinates);
if ((std::abs(result) < 1e-3) &&
(std::abs(coordinates(0)) < 1e-3) &&
(std::abs(coordinates(1)) < 1e-3))
{
++successes;
break; // No need to continue.
}
}
REQUIRE(successes >= 1);
ExponentialSchedule schedule;
// The convergence is very sensitive to the choices of maxMove and initMove.
// SA<> sa(schedule, 2000000, 100, 50, 1000, 1e-12, 2, 2.0, 0.5, 0.1);
SA<> sa(schedule, 2000000, 100, 50, 1000, 1e-12, 2, 2.0, 0.5, 0.1);
FunctionTest<RastriginFunction>(sa, 0.01, 0.001, 4);
}
+12 -114
View File
@@ -22,28 +22,11 @@ using namespace ens::test;
*/
TEST_CASE("SARAHLogisticRegressionTest","[SARAHTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run SARAH with a couple of batch sizes.
// Run SARAH with a couple of batch sizes.
for (size_t batchSize = 35; batchSize < 45; batchSize += 5)
{
SARAH optimizer(0.01, batchSize, 250, 0, 1e-5, true);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.015, 0.015);
}
}
@@ -53,28 +36,11 @@ TEST_CASE("SARAHLogisticRegressionTest","[SARAHTest]")
*/
TEST_CASE("SARAHPlusLogisticRegressionTest","[SARAHTest]")
{
arma::mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run SARAH_Plus with a couple of batch sizes.
// Run SARAH_Plus with a couple of batch sizes.
for (size_t batchSize = 35; batchSize < 45; batchSize += 5)
{
SARAH_Plus optimizer(0.01, batchSize, 250, 0, 1e-5, true);
LogisticRegression<> lr(shuffledData, shuffledResponses, 0.5);
arma::mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest(optimizer, 0.015, 0.015);
}
}
@@ -84,28 +50,11 @@ TEST_CASE("SARAHPlusLogisticRegressionTest","[SARAHTest]")
*/
TEST_CASE("SARAHLogisticRegressionFMatTest","[SARAHTest]")
{
arma::fmat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run SARAH with a couple of batch sizes.
// Run SARAH with a couple of batch sizes.
for (size_t batchSize = 35; batchSize < 45; batchSize += 5)
{
SARAH optimizer(0.01, batchSize, 250, 0, 1e-5, true);
LogisticRegression<arma::fmat> lr(shuffledData, shuffledResponses, 0.5);
arma::fmat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.015, 0.015);
}
}
@@ -115,28 +64,11 @@ TEST_CASE("SARAHLogisticRegressionFMatTest","[SARAHTest]")
*/
TEST_CASE("SARAHPlusLogisticRegressionFMatTest","[SARAHTest]")
{
arma::fmat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run SARAH_Plus with a couple of batch sizes.
// Run SARAH_Plus with a couple of batch sizes.
for (size_t batchSize = 35; batchSize < 45; batchSize += 5)
{
SARAH_Plus optimizer(0.01, batchSize, 250, 0, 1e-5, true);
LogisticRegression<arma::fmat> lr(shuffledData, shuffledResponses, 0.5);
arma::fmat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.015, 0.015);
}
}
@@ -149,28 +81,11 @@ TEST_CASE("SARAHPlusLogisticRegressionFMatTest","[SARAHTest]")
*/
TEST_CASE("SARAHLogisticRegressionSpMatTest","[SARAHTest]")
{
arma::sp_mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run SARAH with a couple of batch sizes.
// Run SARAH with a couple of batch sizes.
for (size_t batchSize = 35; batchSize < 45; batchSize += 5)
{
SARAH optimizer(0.01, batchSize, 250, 0, 1e-5, true);
LogisticRegression<arma::sp_mat> lr(shuffledData, shuffledResponses, 0.5);
arma::sp_mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest<arma::sp_mat>(optimizer, 0.015, 0.015);
}
}
@@ -180,28 +95,11 @@ TEST_CASE("SARAHLogisticRegressionSpMatTest","[SARAHTest]")
*/
TEST_CASE("SARAHPlusLogisticRegressionSpMatTest","[SARAHTest]")
{
arma::sp_mat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
// Now run SARAH_Plus with a couple of batch sizes.
// Run SARAH_Plus with a couple of batch sizes.
for (size_t batchSize = 35; batchSize < 45; batchSize += 5)
{
SARAH_Plus optimizer(0.01, batchSize, 250, 0, 1e-5, true);
LogisticRegression<arma::sp_mat> lr(shuffledData, shuffledResponses, 0.5);
arma::sp_mat coordinates = lr.GetInitialPoint();
optimizer.Optimize(lr, coordinates);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses, coordinates);
REQUIRE(acc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses,
coordinates);
REQUIRE(testAcc == Approx(100.0).epsilon(0.015)); // 1.5% error tolerance.
LogisticRegressionFunctionTest<arma::sp_mat>(optimizer, 0.015, 0.015);
}
}

Some files were not shown because too many files have changed in this diff Show More