summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/test
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/test')
-rw-r--r--ml/dlib/dlib/test/CMakeLists.txt181
-rw-r--r--ml/dlib/dlib/test/WINDOWS_build_and_run_all_unit_tests.bat42
-rw-r--r--ml/dlib/dlib/test/active_learning.cpp165
-rw-r--r--ml/dlib/dlib/test/any.cpp139
-rw-r--r--ml/dlib/dlib/test/any_function.cpp253
-rw-r--r--ml/dlib/dlib/test/array.cpp669
-rw-r--r--ml/dlib/dlib/test/array2d.cpp580
-rw-r--r--ml/dlib/dlib/test/assignment_learning.cpp379
-rw-r--r--ml/dlib/dlib/test/base64.cpp208
-rw-r--r--ml/dlib/dlib/test/bayes_nets.cpp411
-rw-r--r--ml/dlib/dlib/test/bigint.cpp522
-rw-r--r--ml/dlib/dlib/test/binary_search_tree.h889
-rw-r--r--ml/dlib/dlib/test/binary_search_tree_kernel_1a.cpp47
-rw-r--r--ml/dlib/dlib/test/binary_search_tree_kernel_2a.cpp45
-rw-r--r--ml/dlib/dlib/test/binary_search_tree_mm1.cpp66
-rw-r--r--ml/dlib/dlib/test/binary_search_tree_mm2.cpp48
-rw-r--r--ml/dlib/dlib/test/blas_bindings/CMakeLists.txt33
-rw-r--r--ml/dlib/dlib/test/blas_bindings/blas_bindings_dot.cpp314
-rw-r--r--ml/dlib/dlib/test/blas_bindings/blas_bindings_gemm.cpp311
-rw-r--r--ml/dlib/dlib/test/blas_bindings/blas_bindings_gemv.cpp226
-rw-r--r--ml/dlib/dlib/test/blas_bindings/blas_bindings_ger.cpp200
-rw-r--r--ml/dlib/dlib/test/blas_bindings/blas_bindings_scal_axpy.cpp261
-rw-r--r--ml/dlib/dlib/test/blas_bindings/vector.cpp115
-rw-r--r--ml/dlib/dlib/test/bridge.cpp259
-rw-r--r--ml/dlib/dlib/test/bsp.cpp566
-rw-r--r--ml/dlib/dlib/test/byte_orderer.cpp111
-rw-r--r--ml/dlib/dlib/test/cca.cpp460
-rw-r--r--ml/dlib/dlib/test/checkerboard.h55
-rw-r--r--ml/dlib/dlib/test/clustering.cpp410
-rw-r--r--ml/dlib/dlib/test/cmd_line_parser.cpp40
-rw-r--r--ml/dlib/dlib/test/cmd_line_parser.h901
-rw-r--r--ml/dlib/dlib/test/cmd_line_parser_wchar_t.cpp40
-rw-r--r--ml/dlib/dlib/test/compress_stream.cpp306
-rw-r--r--ml/dlib/dlib/test/conditioning_class.cpp86
-rw-r--r--ml/dlib/dlib/test/conditioning_class.h841
-rw-r--r--ml/dlib/dlib/test/conditioning_class_c.cpp87
-rw-r--r--ml/dlib/dlib/test/config_reader.cpp509
-rw-r--r--ml/dlib/dlib/test/correlation_tracker.cpp955
-rw-r--r--ml/dlib/dlib/test/crc32.cpp74
-rw-r--r--ml/dlib/dlib/test/create_iris_datafile.cpp65
-rw-r--r--ml/dlib/dlib/test/create_iris_datafile.h19
-rw-r--r--ml/dlib/dlib/test/cublas.cpp198
-rw-r--r--ml/dlib/dlib/test/data_io.cpp227
-rw-r--r--ml/dlib/dlib/test/directed_graph.cpp541
-rw-r--r--ml/dlib/dlib/test/discriminant_pca.cpp365
-rw-r--r--ml/dlib/dlib/test/disjoint_subsets.cpp102
-rw-r--r--ml/dlib/dlib/test/disjoint_subsets_sized.cpp143
-rw-r--r--ml/dlib/dlib/test/dnn.cpp3261
-rw-r--r--ml/dlib/dlib/test/ekm_and_lisf.cpp306
-rw-r--r--ml/dlib/dlib/test/elastic_net.cpp122
-rw-r--r--ml/dlib/dlib/test/empirical_kernel_map.cpp444
-rw-r--r--ml/dlib/dlib/test/entropy_coder.cpp587
-rw-r--r--ml/dlib/dlib/test/entropy_encoder_model.cpp198
-rw-r--r--ml/dlib/dlib/test/example.cpp72
-rw-r--r--ml/dlib/dlib/test/example_args.cpp75
-rw-r--r--ml/dlib/dlib/test/examples/CMakeLists.txt8
-rw-r--r--ml/dlib/dlib/test/face.cpp360
-rw-r--r--ml/dlib/dlib/test/fft.cpp553
-rw-r--r--ml/dlib/dlib/test/fhog.cpp684
-rw-r--r--ml/dlib/dlib/test/filtering.cpp166
-rw-r--r--ml/dlib/dlib/test/find_max_factor_graph_nmplp.cpp787
-rw-r--r--ml/dlib/dlib/test/find_max_factor_graph_viterbi.cpp217
-rw-r--r--ml/dlib/dlib/test/find_optimal_parameters.cpp58
-rw-r--r--ml/dlib/dlib/test/geometry.cpp883
-rw-r--r--ml/dlib/dlib/test/global_optimization.cpp302
-rw-r--r--ml/dlib/dlib/test/graph.cpp414
-rw-r--r--ml/dlib/dlib/test/graph_cuts.cpp1217
-rw-r--r--ml/dlib/dlib/test/graph_labeler.cpp472
-rw-r--r--ml/dlib/dlib/test/gui/CMakeLists.txt20
-rw-r--r--ml/dlib/dlib/test/gui/main.cpp840
-rw-r--r--ml/dlib/dlib/test/hash.cpp369
-rw-r--r--ml/dlib/dlib/test/hash_map.cpp450
-rw-r--r--ml/dlib/dlib/test/hash_set.cpp387
-rw-r--r--ml/dlib/dlib/test/hash_table.cpp663
-rw-r--r--ml/dlib/dlib/test/hog_image.cpp126
-rw-r--r--ml/dlib/dlib/test/image.cpp1903
-rw-r--r--ml/dlib/dlib/test/iosockstream.cpp181
-rw-r--r--ml/dlib/dlib/test/is_same_object.cpp141
-rw-r--r--ml/dlib/dlib/test/isotonic_regression.cpp103
-rw-r--r--ml/dlib/dlib/test/kcentroid.cpp684
-rw-r--r--ml/dlib/dlib/test/kernel_matrix.cpp161
-rw-r--r--ml/dlib/dlib/test/kmeans.cpp163
-rw-r--r--ml/dlib/dlib/test/learning_to_track.cpp306
-rw-r--r--ml/dlib/dlib/test/least_squares.cpp452
-rw-r--r--ml/dlib/dlib/test/linear_manifold_regularizer.cpp408
-rw-r--r--ml/dlib/dlib/test/lspi.cpp258
-rw-r--r--ml/dlib/dlib/test/lz77_buffer.cpp569
-rw-r--r--ml/dlib/dlib/test/main.cpp217
-rw-r--r--ml/dlib/dlib/test/makefile185
-rw-r--r--ml/dlib/dlib/test/map.cpp441
-rw-r--r--ml/dlib/dlib/test/matrix.cpp1519
-rw-r--r--ml/dlib/dlib/test/matrix2.cpp1158
-rw-r--r--ml/dlib/dlib/test/matrix3.cpp1134
-rw-r--r--ml/dlib/dlib/test/matrix4.cpp1119
-rw-r--r--ml/dlib/dlib/test/matrix_chol.cpp182
-rw-r--r--ml/dlib/dlib/test/matrix_eig.cpp245
-rw-r--r--ml/dlib/dlib/test/matrix_lu.cpp223
-rw-r--r--ml/dlib/dlib/test/matrix_qr.cpp208
-rw-r--r--ml/dlib/dlib/test/max_cost_assignment.cpp157
-rw-r--r--ml/dlib/dlib/test/max_sum_submatrix.cpp177
-rw-r--r--ml/dlib/dlib/test/md5.cpp71
-rw-r--r--ml/dlib/dlib/test/member_function_pointer.cpp553
-rw-r--r--ml/dlib/dlib/test/metaprogramming.cpp94
-rw-r--r--ml/dlib/dlib/test/mpc.cpp346
-rw-r--r--ml/dlib/dlib/test/multithreaded_object.cpp321
-rw-r--r--ml/dlib/dlib/test/numerical_integration.cpp228
-rw-r--r--ml/dlib/dlib/test/object_detector.cpp1028
-rw-r--r--ml/dlib/dlib/test/oca.cpp244
-rw-r--r--ml/dlib/dlib/test/one_vs_all_trainer.cpp305
-rw-r--r--ml/dlib/dlib/test/one_vs_one_trainer.cpp218
-rw-r--r--ml/dlib/dlib/test/opt_qp_solver.cpp813
-rw-r--r--ml/dlib/dlib/test/optimization.cpp1231
-rw-r--r--ml/dlib/dlib/test/optimization_test_functions.cpp425
-rw-r--r--ml/dlib/dlib/test/optimization_test_functions.h310
-rw-r--r--ml/dlib/dlib/test/parallel_for.cpp334
-rw-r--r--ml/dlib/dlib/test/parse.cpp233
-rw-r--r--ml/dlib/dlib/test/pipe.cpp688
-rw-r--r--ml/dlib/dlib/test/pixel.cpp777
-rw-r--r--ml/dlib/dlib/test/probabilistic.cpp123
-rw-r--r--ml/dlib/dlib/test/pyramid_down.cpp424
-rw-r--r--ml/dlib/dlib/test/queue.cpp426
-rw-r--r--ml/dlib/dlib/test/rand.cpp436
-rw-r--r--ml/dlib/dlib/test/random_forest.cpp405
-rw-r--r--ml/dlib/dlib/test/ranking.cpp485
-rw-r--r--ml/dlib/dlib/test/read_write_mutex.cpp208
-rw-r--r--ml/dlib/dlib/test/reference_counter.cpp122
-rw-r--r--ml/dlib/dlib/test/rls.cpp196
-rw-r--r--ml/dlib/dlib/test/sammon.cpp211
-rw-r--r--ml/dlib/dlib/test/scan_image.cpp713
-rw-r--r--ml/dlib/dlib/test/sequence.cpp312
-rw-r--r--ml/dlib/dlib/test/sequence_labeler.cpp461
-rw-r--r--ml/dlib/dlib/test/sequence_segmenter.cpp294
-rw-r--r--ml/dlib/dlib/test/serialize.cpp1087
-rw-r--r--ml/dlib/dlib/test/set.cpp464
-rw-r--r--ml/dlib/dlib/test/sldf.cpp296
-rw-r--r--ml/dlib/dlib/test/sliding_buffer.cpp439
-rw-r--r--ml/dlib/dlib/test/smart_pointers.cpp449
-rw-r--r--ml/dlib/dlib/test/sockets.cpp247
-rw-r--r--ml/dlib/dlib/test/sockets2.cpp204
-rw-r--r--ml/dlib/dlib/test/sockstreambuf.cpp253
-rw-r--r--ml/dlib/dlib/test/sparse_vector.cpp301
-rw-r--r--ml/dlib/dlib/test/stack.cpp294
-rw-r--r--ml/dlib/dlib/test/static_map.cpp323
-rw-r--r--ml/dlib/dlib/test/static_set.cpp206
-rw-r--r--ml/dlib/dlib/test/statistics.cpp915
-rw-r--r--ml/dlib/dlib/test/std_vector_c.cpp101
-rw-r--r--ml/dlib/dlib/test/string.cpp329
-rw-r--r--ml/dlib/dlib/test/svm.cpp661
-rw-r--r--ml/dlib/dlib/test/svm_c_linear.cpp392
-rw-r--r--ml/dlib/dlib/test/svm_c_linear_dcd.cpp545
-rw-r--r--ml/dlib/dlib/test/svm_multiclass_linear.cpp226
-rw-r--r--ml/dlib/dlib/test/svm_struct.cpp641
-rw-r--r--ml/dlib/dlib/test/svr_linear_trainer.cpp161
-rw-r--r--ml/dlib/dlib/test/symmetric_matrix_cache.cpp212
-rw-r--r--ml/dlib/dlib/test/tester.cpp175
-rw-r--r--ml/dlib/dlib/test/tester.h187
-rw-r--r--ml/dlib/dlib/test/thread_pool.cpp428
-rw-r--r--ml/dlib/dlib/test/threads.cpp158
-rw-r--r--ml/dlib/dlib/test/timer.cpp347
-rw-r--r--ml/dlib/dlib/test/tokenizer.cpp378
-rw-r--r--ml/dlib/dlib/test/tools/CMakeLists.txt5
-rw-r--r--ml/dlib/dlib/test/trust_region.cpp329
-rw-r--r--ml/dlib/dlib/test/tuple.cpp186
-rw-r--r--ml/dlib/dlib/test/type_safe_union.cpp455
-rw-r--r--ml/dlib/dlib/test/vectorstream.cpp142
165 files changed, 64370 insertions, 0 deletions
diff --git a/ml/dlib/dlib/test/CMakeLists.txt b/ml/dlib/dlib/test/CMakeLists.txt
new file mode 100644
index 000000000..d6147cb0e
--- /dev/null
+++ b/ml/dlib/dlib/test/CMakeLists.txt
@@ -0,0 +1,181 @@
+#
+# This is a CMake makefile. You can find the cmake utility and
+# information about it at http://www.cmake.org
+#
+
+cmake_minimum_required(VERSION 2.8.12)
+
+# create a variable called target_name and set it to the string "dtest"
+set (target_name dtest)
+PROJECT(${target_name})
+
+# compile the dlib/all/source.cpp file into its own object just to make sure it compiles
+set(DLIB_TEST_COMPILE_ALL_SOURCE_CPP ON)
+
+add_subdirectory(.. dlib_build)
+
+# This variable contains a list of all the tests we are building
+# into the regression test suite.
+set (tests
+ example.cpp
+ active_learning.cpp
+ any.cpp
+ any_function.cpp
+ array2d.cpp
+ array.cpp
+ assignment_learning.cpp
+ base64.cpp
+ bayes_nets.cpp
+ bigint.cpp
+ binary_search_tree_kernel_1a.cpp
+ binary_search_tree_kernel_2a.cpp
+ binary_search_tree_mm1.cpp
+ binary_search_tree_mm2.cpp
+ bridge.cpp
+ bsp.cpp
+ byte_orderer.cpp
+ cca.cpp
+ clustering.cpp
+ cmd_line_parser.cpp
+ cmd_line_parser_wchar_t.cpp
+ compress_stream.cpp
+ conditioning_class_c.cpp
+ conditioning_class.cpp
+ config_reader.cpp
+ correlation_tracker.cpp
+ crc32.cpp
+ create_iris_datafile.cpp
+ data_io.cpp
+ directed_graph.cpp
+ discriminant_pca.cpp
+ disjoint_subsets.cpp
+ disjoint_subsets_sized.cpp
+ ekm_and_lisf.cpp
+ empirical_kernel_map.cpp
+ entropy_coder.cpp
+ entropy_encoder_model.cpp
+ example_args.cpp
+ face.cpp
+ fft.cpp
+ fhog.cpp
+ filtering.cpp
+ find_max_factor_graph_nmplp.cpp
+ find_max_factor_graph_viterbi.cpp
+ geometry.cpp
+ graph.cpp
+ graph_cuts.cpp
+ graph_labeler.cpp
+ hash.cpp
+ hash_map.cpp
+ hash_set.cpp
+ hash_table.cpp
+ hog_image.cpp
+ image.cpp
+ iosockstream.cpp
+ is_same_object.cpp
+ isotonic_regression.cpp
+ kcentroid.cpp
+ kernel_matrix.cpp
+ kmeans.cpp
+ learning_to_track.cpp
+ least_squares.cpp
+ linear_manifold_regularizer.cpp
+ lspi.cpp
+ lz77_buffer.cpp
+ map.cpp
+ matrix2.cpp
+ matrix3.cpp
+ matrix4.cpp
+ matrix_chol.cpp
+ matrix.cpp
+ matrix_eig.cpp
+ matrix_lu.cpp
+ matrix_qr.cpp
+ max_cost_assignment.cpp
+ max_sum_submatrix.cpp
+ md5.cpp
+ member_function_pointer.cpp
+ metaprogramming.cpp
+ mpc.cpp
+ multithreaded_object.cpp
+ numerical_integration.cpp
+ object_detector.cpp
+ oca.cpp
+ one_vs_all_trainer.cpp
+ one_vs_one_trainer.cpp
+ optimization.cpp
+ optimization_test_functions.cpp
+ global_optimization.cpp
+ opt_qp_solver.cpp
+ parallel_for.cpp
+ parse.cpp
+ pipe.cpp
+ pixel.cpp
+ probabilistic.cpp
+ pyramid_down.cpp
+ queue.cpp
+ rand.cpp
+ ranking.cpp
+ read_write_mutex.cpp
+ reference_counter.cpp
+ rls.cpp
+ random_forest.cpp
+ sammon.cpp
+ scan_image.cpp
+ sequence.cpp
+ sequence_labeler.cpp
+ sequence_segmenter.cpp
+ serialize.cpp
+ set.cpp
+ sldf.cpp
+ sliding_buffer.cpp
+ sockets2.cpp
+ sockets.cpp
+ sockstreambuf.cpp
+ sparse_vector.cpp
+ stack.cpp
+ static_map.cpp
+ static_set.cpp
+ statistics.cpp
+ std_vector_c.cpp
+ string.cpp
+ svm_c_linear.cpp
+ svm_c_linear_dcd.cpp
+ svm.cpp
+ svm_multiclass_linear.cpp
+ svm_struct.cpp
+ svr_linear_trainer.cpp
+ symmetric_matrix_cache.cpp
+ thread_pool.cpp
+ threads.cpp
+ timer.cpp
+ tokenizer.cpp
+ trust_region.cpp
+ tuple.cpp
+ type_safe_union.cpp
+ vectorstream.cpp
+ dnn.cpp
+ cublas.cpp
+ find_optimal_parameters.cpp
+ elastic_net.cpp
+ )
+
+
+# add all the cpp files we want to compile to this list. This tells
+# cmake that they are part of our target (which is the executable named dtest)
+ADD_EXECUTABLE(${target_name} main.cpp tester.cpp ${tests})
+
+# Turn on all warnings when using gcc.
+if (CMAKE_COMPILER_IS_GNUCXX)
+ add_definitions("-W -Wall")
+endif()
+
+
+TARGET_LINK_LIBRARIES(${target_name} dlib::dlib )
+
+
+if (NOT DLIB_NO_GUI_SUPPORT)
+ add_subdirectory(gui)
+ add_subdirectory(examples)
+ add_subdirectory(tools)
+endif()
diff --git a/ml/dlib/dlib/test/WINDOWS_build_and_run_all_unit_tests.bat b/ml/dlib/dlib/test/WINDOWS_build_and_run_all_unit_tests.bat
new file mode 100644
index 000000000..0cacfa631
--- /dev/null
+++ b/ml/dlib/dlib/test/WINDOWS_build_and_run_all_unit_tests.bat
@@ -0,0 +1,42 @@
+date /T > test_log.txt
+time /T >> test_log.txt
+
+rem the pings are to wait between builds so visual studio doesn't get in a funk.
+
+
+
+echo testing python >> test_log.txt
+rmdir /S /Q build_python
+mkdir build_python
+cd build_python
+cmake -G "Visual Studio 14 2015 Win64" ../../../tools/python -DPYTHON3=ON
+cmake --build . --config Release --target install || exit /B
+ping 127.0.0.1 -n 5 -w 1000 > null
+cd ..
+
+
+
+echo testing vc2015 >> test_log.txt
+rmdir /S /Q build_vc2015_64
+mkdir build_vc2015_64
+cd build_vc2015_64
+cmake -G "Visual Studio 14 2015 Win64" ..
+cmake --build . --config Release || exit /B
+ping 127.0.0.1 -n 5 -w 1000 > null
+cmake --build . --config Debug || exit /B
+ping 127.0.0.1 -n 5 -w 1000 > null
+cd Release
+dtest --runall -d || exit /B
+cd ..
+cd ..
+
+
+
+
+
+del null
+type test_log.txt
+
+date /T
+time /T
+
diff --git a/ml/dlib/dlib/test/active_learning.cpp b/ml/dlib/dlib/test/active_learning.cpp
new file mode 100644
index 000000000..9dc0013a5
--- /dev/null
+++ b/ml/dlib/dlib/test/active_learning.cpp
@@ -0,0 +1,165 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/svm.h>
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.active_learning");
+
+// ----------------------------------------------------------------------------------------
+
+ typedef matrix<double, 0, 1> sample_type;
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+// ----------------------------------------------------------------------------------------
+
+ void make_dataset (
+ std::vector<sample_type>& samples,
+ std::vector<double>& labels
+ )
+ {
+ for (int r = -10; r <= 10; ++r)
+ {
+ for (int c = -10; c <= 10; ++c)
+ {
+ sample_type samp(2);
+ samp(0) = r;
+ samp(1) = c;
+ samples.push_back(samp);
+
+ // if this point is less than 10 from the origin
+ if (sqrt((double)r*r + c*c) <= 8)
+ labels.push_back(+1);
+ else
+ labels.push_back(-1);
+
+ }
+ }
+
+
+ vector_normalizer<sample_type> normalizer;
+ normalizer.train(samples);
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ samples[i] = normalizer(samples[i]);
+
+ randomize_samples(samples, labels);
+
+ /*
+ cout << "samples.size(): " << samples.size() << endl;
+ cout << "num +1 samples: "<< sum(mat(labels) > 0) << endl;
+ cout << "num -1 samples: "<< sum(mat(labels) < 0) << endl;
+ */
+
+ empirical_kernel_map<kernel_type> ekm;
+ ekm.load(kernel_type(0.15), samples);
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ samples[i] = ekm.project(samples[i]);
+
+ //cout << "dims: "<< ekm.out_vector_size() << endl;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ double test_rank_unlabeled_training_samples (
+ const std::vector<sample_type>& samples,
+ const std::vector<double>& labels,
+ active_learning_mode mode,
+ int iterations,
+ bool pick_front
+ )
+ {
+ matrix<double,2,1> s;
+ s = sum(mat(labels) > 0), sum(mat(labels) < 0);
+ s /= labels.size();
+
+
+ svm_c_linear_dcd_trainer<linear_kernel<sample_type> > trainer;
+ trainer.set_c(25);
+
+ const unsigned long initial_size = 1;
+ std::vector<sample_type> tsamples(samples.begin(), samples.begin()+initial_size);
+ std::vector<double> tlabels(labels.begin(), labels.begin()+initial_size);
+
+ decision_function<linear_kernel<sample_type> > df;
+
+ double random_score = 0;
+ double active_learning_score = 0;
+ for (int i = 0; i < iterations; ++i)
+ {
+ print_spinner();
+ random_subset_selector<sample_type> sss = randomly_subsample(samples,50,i);
+ random_subset_selector<double> ssl = randomly_subsample(labels,50,i);
+ std::vector<unsigned long> results;
+
+ results = rank_unlabeled_training_samples(trainer, tsamples, tlabels, sss, mode);
+
+ const unsigned long idx = pick_front ? results.front() : results.back();
+ tsamples.push_back(sss[idx]);
+ tlabels.push_back(ssl[idx]);
+
+ df = trainer.train(tsamples, tlabels);
+ //cout << "tsamples.size(): " << tsamples.size() << endl;
+ const unsigned long num = tsamples.size();
+ const double active = test_binary_decision_function(df, samples, labels)*s;
+ //cout << "test: "<< active;
+ df = trainer.train(randomly_subsample(samples,num,i), randomly_subsample(labels,num,i));
+ const double random = test_binary_decision_function(df, samples, labels)*s;
+ //cout << "test: "<< random << endl;
+
+ active_learning_score += active;
+ random_score += random;
+
+ //cout << "\n\n***********\n\n" << flush;
+ }
+
+ dlog << LINFO << "pick_front: " << pick_front << " mode: "<< mode;
+ dlog << LINFO << "active_learning_score: "<< active_learning_score;
+ dlog << LINFO << "random_score: "<< random_score;
+ return active_learning_score / random_score;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_active_learning : public tester
+ {
+ public:
+ test_active_learning (
+ ) :
+ tester ("test_active_learning",
+ "Runs tests on the active learning components.")
+ {}
+
+ void perform_test (
+ )
+ {
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+ print_spinner();
+ make_dataset(samples, labels);
+ dlog << LINFO << "samples.size(): "<< samples.size();
+
+ // When we pick the best/front ranked element then the active learning method
+ // shouldn't do much worse than random selection (and often much better).
+ DLIB_TEST(test_rank_unlabeled_training_samples(samples, labels, max_min_margin, 35, true) >= 0.97);
+ DLIB_TEST(test_rank_unlabeled_training_samples(samples, labels, ratio_margin, 25, true) >= 0.96);
+ // However, picking the worst ranked element should do way worse than random
+ // selection.
+ DLIB_TEST(test_rank_unlabeled_training_samples(samples, labels, max_min_margin, 25, false) < 0.8);
+ DLIB_TEST(test_rank_unlabeled_training_samples(samples, labels, ratio_margin, 25, false) < 0.8);
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/any.cpp b/ml/dlib/dlib/test/any.cpp
new file mode 100644
index 000000000..355d00b31
--- /dev/null
+++ b/ml/dlib/dlib/test/any.cpp
@@ -0,0 +1,139 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/any.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../rand.h"
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.any");
+
+// ----------------------------------------------------------------------------------------
+
+ void test_contains_4(
+ const any a
+ )
+ {
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<int>() == true);
+ DLIB_TEST(a.contains<double>() == false);
+ DLIB_TEST(any_cast<int>(a) == 4);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_test()
+ {
+ any a, b, c;
+
+ DLIB_TEST(a.is_empty());
+ DLIB_TEST(a.contains<int>() == false);
+ DLIB_TEST(a.contains<string>() == false);
+ DLIB_TEST(a.is_empty());
+
+ a = b;
+
+ swap(a,b);
+ a.swap(b);
+
+ a = 4;
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<int>() == true);
+ DLIB_TEST(a.contains<double>() == false);
+ DLIB_TEST(any_cast<int>(a) == 4);
+
+ test_contains_4(a);
+
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<int>() == true);
+ DLIB_TEST(a.contains<double>() == false);
+ DLIB_TEST(any_cast<int>(a) == 4);
+
+ bool error = false;
+ try
+ {
+ any_cast<double>(a);
+ }
+ catch (bad_any_cast&)
+ {
+ error = true;
+ }
+ DLIB_TEST(error);
+
+ swap(a,b);
+
+ test_contains_4(b);
+
+ DLIB_TEST(a.is_empty());
+
+ a = b;
+
+ test_contains_4(a);
+
+ c.get<string>() = "test string";
+ DLIB_TEST(c.get<string>() == "test string");
+
+ a = c;
+ DLIB_TEST(a.cast_to<string>() == "test string");
+
+
+ a.clear();
+ DLIB_TEST(a.is_empty());
+ error = false;
+ try
+ {
+ any_cast<string>(a);
+ }
+ catch (bad_any_cast&)
+ {
+ error = true;
+ }
+ DLIB_TEST(error);
+
+
+ a = 1;
+ b = 2;
+
+ int* a_ptr = &a.get<int>();
+ int* b_ptr = &b.get<int>();
+
+ swap(a,b);
+ DLIB_TEST(a_ptr == &b.get<int>());
+ DLIB_TEST(b_ptr == &a.get<int>());
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class any_tester : public tester
+ {
+ public:
+ any_tester (
+ ) :
+ tester ("test_any",
+ "Runs tests on the any component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ run_test();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/any_function.cpp b/ml/dlib/dlib/test/any_function.cpp
new file mode 100644
index 000000000..8defb5988
--- /dev/null
+++ b/ml/dlib/dlib/test/any_function.cpp
@@ -0,0 +1,253 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/any.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../rand.h"
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.any_function");
+
+// ----------------------------------------------------------------------------------------
+
+ int add ( int a, int b) { return a + b; }
+ string cat ( string a, string b) { return a + b; }
+
+// ----------------------------------------------------------------------------------------
+
+ void set_vals1( int& a) { a = 1; }
+ void set_vals2( int& a, int& b) { a = 1; b = 2; }
+ void set_vals3( int& a, int& b, int& c) { a = 1; b = 2; c = 3; }
+ void set_vals4( int& a, int& b, int& c, int& d) { a = 1; b = 2; c = 3; d = 4; }
+ void set_vals5( int& a, int& b, int& c, int& d, int& e) { a = 1; b = 2; c = 3; d = 4; e = 5; }
+ void set_vals6( int& a, int& b, int& c, int& d, int& e, int& f) { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; }
+ void set_vals7( int& a, int& b, int& c, int& d, int& e, int& f, int& g) { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; }
+
+ void set_vals8( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h)
+ { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; }
+
+ void set_vals9( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i)
+ { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; i = 9;}
+
+ void set_vals10( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i, int& j)
+ { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; i = 9; j = 10;}
+
+ void zero_vals( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i, int& j)
+ { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; g = 0; h = 0; i = 0; j = 0;}
+
+// ----------------------------------------------------------------------------------------
+
+ struct test
+ {
+ int operator()() const { return 4; }
+ };
+
+ struct test2
+ {
+ int v;
+
+ test2() : v(0) {}
+ test2(int val) : v(val) {}
+ int operator()() const { return v; }
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ void test_contains_4(
+ const any_function<int()> a
+ )
+ {
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.is_set() == true);
+ DLIB_TEST(a.contains<test>() == true);
+ DLIB_TEST(a.contains<int(*)()>() == false);
+ DLIB_TEST(any_cast<test>(a)() == 4);
+ DLIB_TEST(a() == 4);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_test()
+ {
+ any_function<int()> a, b, c;
+
+ DLIB_TEST(a.is_empty());
+ DLIB_TEST(a.is_set()==false);
+ DLIB_TEST(a.contains<int(*)()>() == false);
+ DLIB_TEST(a.contains<test>() == false);
+ DLIB_TEST(a.is_empty());
+
+ a = b;
+
+ swap(a,b);
+ a.swap(b);
+
+ a = test();
+ test_contains_4(a);
+
+
+ bool error = false;
+ try
+ {
+ any_cast<int(*)()>(a);
+ }
+ catch (bad_any_cast&)
+ {
+ error = true;
+ }
+ DLIB_TEST(error);
+
+ swap(a,b);
+
+ test_contains_4(b);
+
+ DLIB_TEST(a.is_empty());
+
+ a = b;
+
+ test_contains_4(a);
+
+ c.get<test2>() = test2(10);
+ DLIB_TEST(c.get<test2>().v == 10);
+
+ a = c;
+ DLIB_TEST(a.cast_to<test2>().v == 10);
+
+
+ a.clear();
+ DLIB_TEST(a.is_empty());
+ error = false;
+ try
+ {
+ any_cast<test>(a);
+ }
+ catch (bad_any_cast&)
+ {
+ error = true;
+ }
+ DLIB_TEST(error);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_test2()
+ {
+ any_function<int(int,int)> f = &add;
+
+ DLIB_TEST(f(1,3) == 4);
+
+ any_function<string(string,string)> g(&cat);
+ DLIB_TEST(g("one", "two") == "onetwo");
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_test3()
+ {
+ any_function<void(int&)> f1;
+ any_function<void(int&,int&)> f2;
+ any_function<void(int&,int&,int&)> f3;
+ any_function<void(int&,int&,int&,int&)> f4;
+ any_function<void(int&,int&,int&,int&,int&)> f5;
+ any_function<void(int&,int&,int&,int&,int&,int&)> f6;
+ any_function<void(int&,int&,int&,int&,int&,int&,int&)> f7;
+ any_function<void(int&,int&,int&,int&,int&,int&,int&,int&)> f8;
+ any_function<void(int&,int&,int&,int&,int&,int&,int&,int&,int&)> f9;
+ any_function<void(int&,int&,int&,int&,int&,int&,int&,int&,int&,int&)> f10;
+
+ f1 = set_vals1;
+ f2 = set_vals2;
+ f3 = set_vals3;
+ f4 = set_vals4;
+ f5 = set_vals5;
+ f6 = set_vals6;
+ f7 = set_vals7;
+ f8 = set_vals8;
+ f9 = set_vals9;
+ f10 = set_vals10;
+
+ int a,b,c,d,e,f,g,h,i,j;
+
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f1(a);
+ DLIB_TEST(a==1);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f2(a,b);
+ DLIB_TEST(a==1 && b==2);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f3(a,b,c);
+ DLIB_TEST(a==1 && b==2 && c==3);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f4(a,b,c,d);
+ DLIB_TEST(a==1 && b==2 && c==3 && d==4);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f5(a,b,c,d,e);
+ DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f6(a,b,c,d,e,f);
+ DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f7(a,b,c,d,e,f,g);
+ DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f8(a,b,c,d,e,f,g,h);
+ DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f9(a,b,c,d,e,f,g,h,i);
+ DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8 && i==9);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+
+ f10(a,b,c,d,e,f,g,h,i,j);
+ DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8 && i==9 && j==10);
+ zero_vals(a,b,c,d,e,f,g,h,i,j);
+ }
+// ----------------------------------------------------------------------------------------
+
+ class test_any_function : public tester
+ {
+ public:
+ test_any_function (
+ ) :
+ tester ("test_any_function",
+ "Runs tests on the any_function component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ run_test();
+ print_spinner();
+ run_test2();
+ print_spinner();
+ run_test3();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/array.cpp b/ml/dlib/dlib/test/array.cpp
new file mode 100644
index 000000000..55ba1a724
--- /dev/null
+++ b/ml/dlib/dlib/test/array.cpp
@@ -0,0 +1,669 @@
+// Copyright (C) 2005 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/interfaces/enumerable.h>
+#include <dlib/array.h>
+#include <dlib/rand.h>
+
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ using dlib::array;
+
+ logger dlog("test.array");
+
+ template <
+ typename array
+ >
+ void array_expand_test (
+ )
+ /*!
+ requires
+ - array is an implementation of array/array_sort_abstract.h
+ array is instantiated with unsigned long
+ ensures
+ - runs tests on array for compliance with the specs
+ !*/
+ {
+ dlib::rand rnd;
+
+ DLIB_TEST(dlib::is_array<array>::value == true);
+
+ array a1, a2;
+
+ {
+ array a4(4);
+ DLIB_TEST(a4.size() == 4);
+ }
+
+ {
+ array a1, a2;
+
+ for (int k = 1; k < 100000; k += 1000)
+ {
+ for (int i = 0; i < 10; ++i)
+ {
+ a1.clear();
+ a1.set_max_size(500+k);
+ a1.set_size(500+k);
+ for (unsigned long j = 0; j < a1.size(); ++j)
+ {
+ a1[j] = j;
+ DLIB_TEST(a1[j] == j);
+ }
+ }
+ }
+ }
+
+ DLIB_TEST(a1.max_size() == 0);
+ DLIB_TEST(a2.max_size() == 0);
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ swap(a1,a2);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.move_next() == false);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.size() == 0);
+
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ a1.reset();
+ a2.reset();
+
+ for (unsigned long k = 0; k < 4; ++k)
+ {
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ swap(a1,a2);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.move_next() == false);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.size() == 0);
+
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ a1.clear();
+ a2.clear();
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ swap(a1,a2);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.move_next() == false);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.size() == 0);
+
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ a1.clear();
+ a2.clear();
+
+
+
+
+ a1.set_max_size(100000);
+ a2.set_max_size(100000);
+ a1.set_size(10000);
+ DLIB_TEST(a1.size() == 10000);
+ a2.set_size(10000);
+ DLIB_TEST(a2.size() == 10000);
+ for (unsigned long i = 0; i < a1.size(); ++i)
+ {
+ unsigned long a = static_cast<unsigned long>(rnd.get_random_32bit_number());
+ a1[i] = a;
+ a2[i] = i;
+ DLIB_TEST(a1[i] == a);
+ DLIB_TEST(a2[i] == i);
+ }
+
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next());
+ DLIB_TEST(a1.current_element_valid());
+
+ DLIB_TEST(a1.at_start() == false);
+ a1.sort();
+ DLIB_TEST(a1.at_start());
+ a2.sort();
+ DLIB_TEST(a1.size() == 10000);
+ DLIB_TEST(a2.size() == 10000);
+
+
+ for (unsigned long i = 0; i < a1.size(); ++i)
+ {
+ if (i+1 < a1.size())
+ {
+ DLIB_TEST_MSG(a1[i] <= a1[i+1],
+ "a1[i]: " << a1[i] << " a1[i+1]: " << a1[i+1]
+ << " i: " << i);
+ }
+ DLIB_TEST_MSG(a2[i] == i,"i: " << i << " a2[i]: " << a2[i]);
+ }
+
+ unsigned long last = 0;
+ unsigned long count = 0;
+ while (a1.move_next())
+ {
+ DLIB_TEST(last <= a1.element());
+ last = a1.element();
+ ++count;
+ }
+ DLIB_TEST(count == a1.size());
+
+ last = 0;
+ count = 0;
+ while (a2.move_next())
+ {
+ DLIB_TEST(last <= a2.element());
+ last = a2.element();
+ ++count;
+ }
+ DLIB_TEST(count == a2.size());
+
+ a2.set_size(15000);
+
+ for (unsigned long i = 0; i < a1.size(); ++i)
+ {
+ if (i+1 < a1.size())
+ {
+ DLIB_TEST(a1[i] <= a1[i+1]);
+ }
+ DLIB_TEST(a2[i] == i);
+ }
+
+ for (unsigned long i = 10000; i < a2.size(); ++i)
+ {
+ a2[i] = i;
+ DLIB_TEST(a2[i] == i);
+ }
+
+ for (unsigned long i = 0; i < a2.size(); ++i)
+ {
+ DLIB_TEST(a2[i] == i);
+ }
+
+ a2.reset();
+ last = 0;
+ while (a2.move_next())
+ {
+ DLIB_TEST(last <= a2.element());
+ last = a2.element();
+ }
+
+ a1.reset();
+ last = 0;
+ while (a1.move_next())
+ {
+ DLIB_TEST(last <= a1.element());
+ last = a1.element();
+ }
+
+ a1.sort();
+ last = 0;
+ while (a1.move_next())
+ {
+ DLIB_TEST(last <= a1.element());
+ last = a1.element();
+ }
+
+ swap(a2,a1);
+
+ for (unsigned long i = 0; i < 15000; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+
+
+
+ a1.clear();
+ DLIB_TEST(a1.max_size() == 0);
+
+
+
+
+ a1.clear();
+ a2.clear();
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a2.size() == 0);
+ a1.set_max_size(100000);
+ a2.set_max_size(100000);
+
+ a1.set_size(10000);
+ DLIB_TEST(a1.size() == 10000);
+ a2.set_size(10000);
+ DLIB_TEST(a2.size() == 10000);
+ for (unsigned long i = 0; i < a1.size(); ++i)
+ {
+ unsigned long a = static_cast<unsigned long>(rnd.get_random_32bit_number());
+ a1[i] = a;
+ a2[i] = i;
+ DLIB_TEST(a1[i] == a);
+ DLIB_TEST(a2[i] == i);
+ }
+
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next());
+ DLIB_TEST(a1.current_element_valid());
+
+ DLIB_TEST(a1.at_start() == false);
+ a1.sort();
+ DLIB_TEST(a1.at_start());
+ a2.sort();
+ DLIB_TEST(a1.size() == 10000);
+ DLIB_TEST(a2.size() == 10000);
+
+
+ for (unsigned long i = 0; i < a1.size(); ++i)
+ {
+ if (i+1 < a1.size())
+ {
+ DLIB_TEST(a1[i] <= a1[i+1]);
+ }
+ DLIB_TEST(a2[i] == i);
+ }
+
+ last = 0;
+ while (a1.move_next())
+ {
+ DLIB_TEST(last <= a1.element());
+ last = a1.element();
+ }
+
+ last = 0;
+ while (a2.move_next())
+ {
+ DLIB_TEST(last <= a2.element());
+ last = a2.element();
+ }
+
+ a2.set_size(15000);
+
+ for (unsigned long i = 0; i < a1.size(); ++i)
+ {
+ if (i+1 < a1.size())
+ {
+ DLIB_TEST(a1[i] <= a1[i+1]);
+ }
+ DLIB_TEST(a2[i] == i);
+ }
+
+ for (unsigned long i = 10000; i < a2.size(); ++i)
+ {
+ a2[i] = i;
+ DLIB_TEST(a2[i] == i);
+ }
+
+ for (unsigned long i = 0; i < a2.size(); ++i)
+ {
+ DLIB_TEST(a2[i] == i);
+ }
+
+ a2.reset();
+ last = 0;
+ while (a2.move_next())
+ {
+ DLIB_TEST(last <= a2.element());
+ last = a2.element();
+ }
+
+ a1.reset();
+ last = 0;
+ while (a1.move_next())
+ {
+ DLIB_TEST(last <= a1.element());
+ last = a1.element();
+ }
+
+ a1.sort();
+ last = 0;
+ while (a1.move_next())
+ {
+ DLIB_TEST(last <= a1.element());
+ last = a1.element();
+ }
+
+ swap(a2,a1);
+
+ for (unsigned long i = 0; i < 15000; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+
+
+
+ a1.clear();
+ DLIB_TEST(a1.max_size() == 0);
+
+ a2.clear();
+ print_spinner();
+ }
+
+
+
+ a1.set_max_size(2000000);
+ DLIB_TEST(a1.max_size() == 2000000);
+ DLIB_TEST(a1.size() == 0);
+ a1.set_size(2000000);
+ DLIB_TEST(a1.max_size() == 2000000);
+ DLIB_TEST(a1.size() == 2000000);
+
+ for (unsigned long i = 0; i < a1.size(); ++i)
+ {
+ a1[i] = rnd.get_random_32bit_number();
+ }
+
+ print_spinner();
+ a1.sort();
+
+ print_spinner();
+ // serialize the state of a1, then clear a1, then
+ // load the state back into a1.
+ ostringstream sout;
+ serialize(a1,sout);
+ DLIB_TEST(a1.at_start() == true);
+ istringstream sin(sout.str());
+ a1.clear();
+ DLIB_TEST(a1.max_size() == 0);
+ deserialize(a1,sin);
+
+ DLIB_TEST(a1.size() == 2000000);
+
+ for (unsigned long i = 0; i < a1.size()-1; ++i)
+ {
+ DLIB_TEST(a1[i] <= a1[i+1]);
+ }
+
+ DLIB_TEST(a1.max_size() == 2000000);
+ DLIB_TEST(a1.size() == 2000000);
+
+
+ swap(a1,a2);
+
+ print_spinner();
+
+ DLIB_TEST(a2.size() == 2000000);
+
+ for (unsigned long i = 0; i < a2.size()-1; ++i)
+ {
+ DLIB_TEST(a2[i] <= a2[i+1]);
+ }
+
+ DLIB_TEST(a2.max_size() == 2000000);
+ DLIB_TEST(a2.size() == 2000000);
+
+ swap(a1,a2);
+
+
+ a1.clear();
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.max_size() == 0);
+
+ a1.resize(10);
+ DLIB_TEST(a1.size() == 10);
+ DLIB_TEST(a1.max_size() == 10);
+
+ for (unsigned long i = 0; i < a1.size(); ++i)
+ {
+ a1[i] = i;
+ }
+
+ print_spinner();
+ a1.resize(100);
+ DLIB_TEST(a1.size() == 100);
+ DLIB_TEST(a1.max_size() == 100);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+
+ a1.resize(50);
+ DLIB_TEST(a1.size() == 50);
+ DLIB_TEST(a1.max_size() == 100);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+
+ a1.resize(10);
+ DLIB_TEST(a1.size() == 10);
+ DLIB_TEST(a1.max_size() == 100);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+
+ a1.resize(20);
+ DLIB_TEST(a1.size() == 20);
+ DLIB_TEST(a1.max_size() == 100);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+
+
+ a1.resize(100);
+ DLIB_TEST(a1.size() == 100);
+ DLIB_TEST(a1.max_size() == 100);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+
+ {
+ a1.clear();
+ DLIB_TEST(a1.size() == 0);
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ unsigned long a = i;
+ a1.push_back(a);
+ DLIB_TEST(a1.size() == i+1);
+ DLIB_TEST(a1.back() == i);
+ }
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ unsigned long a = 0;
+ a1.pop_back(a);
+ DLIB_TEST(a == 99-i);
+ }
+ }
+
+ {
+ a1.clear();
+ DLIB_TEST(a1.size() == 0);
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ unsigned long a = i;
+ a1.push_back(a);
+ DLIB_TEST(a1.size() == i+1);
+ DLIB_TEST(a1.back() == i);
+ }
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ DLIB_TEST(a1[i] == i);
+ }
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ a1.pop_back();
+ }
+ DLIB_TEST(a1.size() == 0);
+ }
+
+ }
+
+ struct stuff
+ {
+ int whatever;
+ };
+ void another_array_test()
+ {
+ array<stuff> a;
+ a.resize(5);
+ a[0].whatever = 0;
+ stuff temp;
+ temp.whatever = 99;
+ a.push_back(temp);
+ DLIB_TEST(a.size() == 6);
+ DLIB_TEST(a[5].whatever == 99);
+
+ DLIB_TEST(dlib::is_array<array<stuff> >::value == true);
+ }
+
+ void test_array_split()
+ {
+ array<int> temp(5);
+
+ for (unsigned int i = 0; i < temp.size(); ++i)
+ temp[i] = i;
+
+ array<int> b;
+
+ split_array(temp, b, 0.5);
+ DLIB_TEST(temp.size() == 2);
+ DLIB_TEST(b.size() == 3);
+
+ DLIB_TEST(temp[0] == 0);
+ DLIB_TEST(temp[1] == 1);
+ DLIB_TEST(b[0] == 2);
+ DLIB_TEST(b[1] == 3);
+ DLIB_TEST(b[2] == 4);
+ }
+
+ class array_tester : public tester
+ {
+ public:
+ array_tester (
+ ) :
+ tester ("test_array",
+ "Runs tests on the array component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ another_array_test();
+
+ // test a checking version first for good measure
+ print_spinner();
+ array_expand_test<array<unsigned long> >();
+
+ DLIB_TEST(dlib::is_array<int>::value == false);
+ test_array_split();
+ }
+ } a;
+
+
+
+
+}
+
diff --git a/ml/dlib/dlib/test/array2d.cpp b/ml/dlib/dlib/test/array2d.cpp
new file mode 100644
index 000000000..12b8b586a
--- /dev/null
+++ b/ml/dlib/dlib/test/array2d.cpp
@@ -0,0 +1,580 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/interfaces/enumerable.h>
+#include <dlib/array2d.h>
+#include "tester.h"
+#include <dlib/pixel.h>
+#include <dlib/image_transforms.h>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.array2d");
+
+ template <
+ typename array2d
+ >
+ void array2d_kernel_test (
+ )
+ /*!
+ requires
+ - array2d is an implementation of array2d/array2d_kernel_abstract.h
+ is instantiated with unsigned long
+ ensures
+ - runs tests on array2d for compliance with the specs
+ !*/
+ {
+ srand(static_cast<unsigned int>(time(0)));
+
+ array2d test,test2;
+
+ long nc, nr;
+
+
+ DLIB_TEST(get_rect(test).is_empty());
+
+ enumerable<unsigned long>& e = test;
+ DLIB_TEST(e.at_start() == true);
+
+
+ DLIB_TEST(e.size() == 0);
+ DLIB_TEST(e.at_start() == true);
+ DLIB_TEST(e.current_element_valid() == false);
+
+ DLIB_TEST (e.move_next() == false);
+ DLIB_TEST (e.move_next() == false);
+ DLIB_TEST (e.move_next() == false);
+ DLIB_TEST (e.move_next() == false);
+ DLIB_TEST (e.move_next() == false);
+ DLIB_TEST (e.move_next() == false);
+
+
+ DLIB_TEST(e.size() == 0);
+ DLIB_TEST(e.at_start() == false);
+ DLIB_TEST(e.current_element_valid() == false);
+
+
+ e.reset();
+
+ DLIB_TEST(e.size() == 0);
+ DLIB_TEST(e.at_start() == true);
+ DLIB_TEST(e.current_element_valid() == false);
+
+
+ DLIB_TEST(get_rect(test).is_empty());
+
+
+
+ DLIB_TEST(test.at_start() == true);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ test.reset();
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ test.clear();
+
+
+ DLIB_TEST(test.at_start() == true);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+
+
+ test.set_size(0,0);
+
+ DLIB_TEST(get_rect(test).is_empty());
+
+ DLIB_TEST(test.at_start() == true);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+ DLIB_TEST (test.move_next() == false);
+
+ swap(test,test2);
+ DLIB_TEST (test2.at_start() == false);
+ DLIB_TEST (test2.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ swap(test,test2);
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.current_element_valid() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ test.reset();
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+
+
+ for (int j = 0; j < 30; ++j)
+ {
+ test2.clear();
+ switch (j)
+ {
+ case 0:
+ nc = 10;
+ nr = 11;
+ break;
+ case 1:
+ nc = 1;
+ nr = 1;
+ break;
+ case 2:
+ nc = 100;
+ nr = 1;
+ break;
+ case 3:
+ nc = 1;
+ nr = 100;
+ break;
+ default:
+ nc = ::rand()%100 + 1;
+ nr = ::rand()%100 + 1;
+ break;
+ }
+
+ test.set_size(nr,nc);
+
+ DLIB_TEST(get_rect(test).left() == 0);
+ DLIB_TEST(get_rect(test).top() == 0);
+ DLIB_TEST(get_rect(test).right() == nc-1);
+ DLIB_TEST(get_rect(test).bottom() == nr-1);
+
+ DLIB_TEST(test.size() == static_cast<unsigned long>(nc*nr));
+ DLIB_TEST(test.nr() == nr);
+ DLIB_TEST(test.nc() == nc);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ unsigned long i = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.current_element_valid() == true);
+ DLIB_TEST(test.at_start() == false);
+ test.element() = i;
+ DLIB_TEST(const_cast<const array2d&>(test).element() == i);
+ ++i;
+ }
+ DLIB_TEST(i == test.size());
+ DLIB_TEST(test.current_element_valid() == false);
+
+ DLIB_TEST(test.nr() == nr);
+ DLIB_TEST(test.nc() == nc);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.size() == static_cast<unsigned long>(nc*nr));
+
+ i = 0;
+ for (long row = 0; row < test.nr(); ++row)
+ {
+ for (long col = 0; col < test.nc(); ++col)
+ {
+ DLIB_TEST_MSG(test[row][col] == i,
+ "\n\trow: " << row <<
+ "\n\tcol: " << col <<
+ "\n\ti: " << i <<
+ "\n\ttest[row][col]: " << test[row][col]);
+ DLIB_TEST(test[row].nc() == test.nc());
+ DLIB_TEST(test.current_element_valid() == false);
+
+ DLIB_TEST(test.nr() == nr);
+ DLIB_TEST(test.nc() == nc);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.size() == static_cast<unsigned long>(nc*nr));
+ ++i;
+ }
+ }
+
+ test.reset();
+
+ i = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element() == i);
+ ++i;
+ DLIB_TEST(test.current_element_valid() == true);
+ DLIB_TEST(test.at_start() == false);
+ }
+ DLIB_TEST(i == test.size());
+
+ test.reset();
+
+
+
+
+ swap(test,test2);
+
+ DLIB_TEST(test2.size() == static_cast<unsigned long>(nc*nr));
+ DLIB_TEST(test2.nr() == nr);
+ DLIB_TEST(test2.nc() == nc);
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.current_element_valid() == false);
+
+ i = 0;
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.at_start() == false);
+ test2.element() = i;
+ ++i;
+ }
+ DLIB_TEST(i == test2.size());
+ DLIB_TEST(test2.current_element_valid() == false);
+
+ DLIB_TEST(test2.nr() == nr);
+ DLIB_TEST(test2.nr() == test2.nr());
+ DLIB_TEST(test2.nc() == nc);
+ DLIB_TEST(test2.nc() == test2.nc());
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.size() == static_cast<unsigned long>(nc*nr));
+
+ i = 0;
+ for (long row = 0; row < test2.nr(); ++row)
+ {
+ for (long col = 0; col < test2.nc(); ++col)
+ {
+ DLIB_TEST(test2[row][col] == i);
+ DLIB_TEST(const_cast<const array2d&>(test2)[row][col] == i);
+ DLIB_TEST(test2[row].nc() == test2.nc());
+ DLIB_TEST(test2.current_element_valid() == false);
+
+ DLIB_TEST(test2.nr() == nr);
+ DLIB_TEST(test2.nr() == test2.nr());
+ DLIB_TEST(test2.nc() == nc);
+ DLIB_TEST(test2.nc() == test2.nc());
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.size() == static_cast<unsigned long>(nc*nr));
+ ++i;
+ }
+ }
+
+ test2.reset();
+
+ i = 0;
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2.element() == i);
+ DLIB_TEST(const_cast<const array2d&>(test2).element() == i);
+ ++i;
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.at_start() == false);
+ }
+ DLIB_TEST(i == test2.size());
+
+
+ test2.clear();
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.nr() == 0);
+ DLIB_TEST(test2.nc() == 0);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == true);
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.nc() == 0);
+ DLIB_TEST(test.nr() == 0);
+
+ test.set_size(nr,nc);
+ DLIB_TEST(test.size() == static_cast<unsigned long>(nc*nr));
+ DLIB_TEST(test.nc() == nc);
+ DLIB_TEST(test.nr() == nr);
+
+
+
+ }
+
+
+
+
+
+ // test the serialization
+ istringstream sin;
+ ostringstream sout;
+ test.clear();
+ test2.clear();
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.nc() == 0);
+ DLIB_TEST(test.nr() == 0);
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.nc() == 0);
+ DLIB_TEST(test2.nr() == 0);
+
+ test.set_size(10,10);
+
+ for (long row = 0; row < test.nr(); ++row)
+ {
+ for (long col = 0; col < test.nc(); ++col)
+ {
+ test[row][col] = row*col;
+ }
+ }
+
+ serialize(test,sout);
+ sin.str(sout.str());
+ deserialize(test2,sin);
+
+ DLIB_TEST(test2.size() == test.size());
+ DLIB_TEST(test2.nc() == test.nc());
+ DLIB_TEST(test2.nr() == test.nr());
+ DLIB_TEST(test2.size() == 100);
+ DLIB_TEST(test2.nc() == 10);
+ DLIB_TEST(test2.nr() == 10);
+
+
+ for (long row = 0; row < test.nr(); ++row)
+ {
+ for (long col = 0; col < test.nc(); ++col)
+ {
+ DLIB_TEST(test[row][col] == static_cast<unsigned long>(row*col));
+ DLIB_TEST(test2[row][col] == static_cast<unsigned long>(row*col));
+ }
+ }
+
+
+
+
+
+
+ test.set_size(10,11);
+ DLIB_TEST(test.nr() == 10);
+ DLIB_TEST(test.nc() == 11);
+ test.set_size(0,0);
+ DLIB_TEST(test.nr() == 0);
+ DLIB_TEST(test.nc() == 0);
+
+ }
+
+ void test_serialization()
+ {
+ // Do these tests because there are overloads of the serialize routines
+ // specifically for these types of pixel (except for unsigned short,
+ // we do that because you can never have too many tests).
+ {
+ array2d<rgb_alpha_pixel> img, img2;
+ img.set_size(3,2);
+ assign_all_pixels(img, 5);
+ img[1][1].red = 9;
+ img[1][1].green = 8;
+ img[1][1].blue = 7;
+ img[1][1].alpha = 3;
+ ostringstream sout;
+ serialize(img, sout);
+ istringstream sin(sout.str());
+ deserialize(img2, sin);
+
+ DLIB_TEST(img2.nr() == 3);
+ DLIB_TEST(img2.nc() == 2);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ DLIB_TEST(img[r][c].red == img2[r][c].red);
+ DLIB_TEST(img[r][c].green == img2[r][c].green);
+ DLIB_TEST(img[r][c].blue == img2[r][c].blue);
+ DLIB_TEST(img[r][c].alpha == img2[r][c].alpha);
+ }
+ }
+ }
+ {
+ array2d<hsi_pixel> img, img2;
+ img.set_size(3,2);
+ assign_all_pixels(img, 5);
+ img[1][1].h = 9;
+ img[1][1].s = 2;
+ img[1][1].i = 3;
+ ostringstream sout;
+ serialize(img, sout);
+ istringstream sin(sout.str());
+ deserialize(img2, sin);
+
+ DLIB_TEST(img2.nr() == 3);
+ DLIB_TEST(img2.nc() == 2);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ DLIB_TEST(img[r][c].h == img2[r][c].h);
+ DLIB_TEST(img[r][c].s == img2[r][c].s);
+ DLIB_TEST(img[r][c].i == img2[r][c].i);
+ }
+ }
+ }
+ {
+ array2d<bgr_pixel> img, img2;
+ img.set_size(3,2);
+ assign_all_pixels(img, 5);
+ img[1][1].red = 1;
+ img[1][1].green = 2;
+ img[1][1].blue = 3;
+ ostringstream sout;
+ serialize(img, sout);
+ istringstream sin(sout.str());
+ deserialize(img2, sin);
+
+ DLIB_TEST(img2.nr() == 3);
+ DLIB_TEST(img2.nc() == 2);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ DLIB_TEST(img[r][c].red == img2[r][c].red);
+ DLIB_TEST(img[r][c].green == img2[r][c].green);
+ DLIB_TEST(img[r][c].blue == img2[r][c].blue);
+ }
+ }
+ }
+ {
+ array2d<rgb_pixel> img, img2;
+ img.set_size(3,2);
+ assign_all_pixels(img, 5);
+ img[1][1].red = 1;
+ img[1][1].green = 2;
+ img[1][1].blue = 3;
+ ostringstream sout;
+ serialize(img, sout);
+ istringstream sin(sout.str());
+ deserialize(img2, sin);
+
+ DLIB_TEST(img2.nr() == 3);
+ DLIB_TEST(img2.nc() == 2);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ DLIB_TEST(img[r][c].red == img2[r][c].red);
+ DLIB_TEST(img[r][c].green == img2[r][c].green);
+ DLIB_TEST(img[r][c].blue == img2[r][c].blue);
+ }
+ }
+ }
+ {
+ array2d<unsigned short> img, img2;
+ img.set_size(3,2);
+ assign_all_pixels(img, 5);
+ img[1][1] = 9;
+ ostringstream sout;
+ serialize(img, sout);
+ istringstream sin(sout.str());
+ deserialize(img2, sin);
+
+ DLIB_TEST(img2.nr() == 3);
+ DLIB_TEST(img2.nc() == 2);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ DLIB_TEST(img[r][c] == img2[r][c]);
+ }
+ }
+ }
+ {
+ array2d<unsigned char> img, img2;
+ img.set_size(3,2);
+ assign_all_pixels(img, 5);
+ img[1][1] = 9;
+ ostringstream sout;
+ serialize(img, sout);
+ istringstream sin(sout.str());
+ deserialize(img2, sin);
+
+ DLIB_TEST(img2.nr() == 3);
+ DLIB_TEST(img2.nc() == 2);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ DLIB_TEST(img[r][c] == img2[r][c]);
+ }
+ }
+
+ DLIB_TEST((char*)&img[0][0] + img.width_step() == (char*)&img[1][0]);
+ }
+
+ COMPILE_TIME_ASSERT(is_array2d<array2d<unsigned char> >::value == true);
+ COMPILE_TIME_ASSERT(is_array2d<array2d<float> >::value == true);
+ COMPILE_TIME_ASSERT(is_array2d<float>::value == false);
+ }
+
+
+ class array2d_tester : public tester
+ {
+ public:
+ array2d_tester (
+ ) :
+ tester ("test_array2d",
+ "Runs tests on the array2d component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ array2d_kernel_test<array2d<unsigned long> >();
+ print_spinner();
+ test_serialization();
+ print_spinner();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/assignment_learning.cpp b/ml/dlib/dlib/test/assignment_learning.cpp
new file mode 100644
index 000000000..bba47db3d
--- /dev/null
+++ b/ml/dlib/dlib/test/assignment_learning.cpp
@@ -0,0 +1,379 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+#include <dlib/rand.h>
+
+
+typedef dlib::matrix<double,3,1> lhs_element;
+typedef dlib::matrix<double,3,1> rhs_element;
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.assignment_learning");
+
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+
+ struct feature_extractor_dense
+ {
+ typedef matrix<double,3,1> feature_vector_type;
+
+ typedef ::lhs_element lhs_element;
+ typedef ::rhs_element rhs_element;
+
+ unsigned long num_features() const
+ {
+ return 3;
+ }
+
+ void get_features (
+ const lhs_element& left,
+ const rhs_element& right,
+ feature_vector_type& feats
+ ) const
+ {
+ feats = squared(left - right);
+ }
+
+ };
+
+ void serialize (const feature_extractor_dense& , std::ostream& ) {}
+ void deserialize (feature_extractor_dense& , std::istream& ) {}
+
+// ----------------------------------------------------------------------------------------
+
+ struct feature_extractor_sparse
+ {
+ typedef std::vector<std::pair<unsigned long,double> > feature_vector_type;
+
+ typedef ::lhs_element lhs_element;
+ typedef ::rhs_element rhs_element;
+
+ unsigned long num_features() const
+ {
+ return 3;
+ }
+
+ void get_features (
+ const lhs_element& left,
+ const rhs_element& right,
+ feature_vector_type& feats
+ ) const
+ {
+ feats.clear();
+ feats.push_back(make_pair(0,squared(left-right)(0)));
+ feats.push_back(make_pair(1,squared(left-right)(1)));
+ feats.push_back(make_pair(2,squared(left-right)(2)));
+ }
+
+ };
+
+ void serialize (const feature_extractor_sparse& , std::ostream& ) {}
+ void deserialize (feature_extractor_sparse& , std::istream& ) {}
+
+// ----------------------------------------------------------------------------------------
+
+ typedef std::pair<std::vector<lhs_element>, std::vector<rhs_element> > sample_type;
+ typedef std::vector<long> label_type;
+
+// ----------------------------------------------------------------------------------------
+
+ void make_data (
+ std::vector<sample_type>& samples,
+ std::vector<label_type>& labels
+ )
+ {
+ lhs_element a, b, c, d;
+ a = 1,0,0;
+ b = 0,1,0;
+ c = 0,0,1;
+ d = 0,1,1;
+
+ std::vector<lhs_element> lhs;
+ std::vector<rhs_element> rhs;
+ label_type label;
+
+ lhs.push_back(a);
+ lhs.push_back(b);
+ lhs.push_back(c);
+
+ rhs.push_back(b);
+ rhs.push_back(a);
+ rhs.push_back(c);
+
+ label.push_back(1);
+ label.push_back(0);
+ label.push_back(2);
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+
+
+
+ lhs.clear();
+ rhs.clear();
+ label.clear();
+
+ lhs.push_back(a);
+ lhs.push_back(b);
+ lhs.push_back(c);
+
+ rhs.push_back(c);
+ rhs.push_back(b);
+ rhs.push_back(a);
+ rhs.push_back(d);
+
+ label.push_back(2);
+ label.push_back(1);
+ label.push_back(0);
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+
+ lhs.clear();
+ rhs.clear();
+ label.clear();
+
+ lhs.push_back(a);
+ lhs.push_back(b);
+ lhs.push_back(c);
+
+ rhs.push_back(c);
+ rhs.push_back(a);
+ rhs.push_back(d);
+
+ label.push_back(1);
+ label.push_back(-1);
+ label.push_back(0);
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+
+
+ lhs.clear();
+ rhs.clear();
+ label.clear();
+
+ lhs.push_back(d);
+ lhs.push_back(b);
+ lhs.push_back(c);
+
+ label.push_back(-1);
+ label.push_back(-1);
+ label.push_back(-1);
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+
+
+ lhs.clear();
+ rhs.clear();
+ label.clear();
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void make_data_force (
+ std::vector<sample_type>& samples,
+ std::vector<label_type>& labels
+ )
+ {
+ lhs_element a, b, c, d;
+ a = 1,0,0;
+ b = 0,1,0;
+ c = 0,0,1;
+ d = 0,1,1;
+
+ std::vector<lhs_element> lhs;
+ std::vector<rhs_element> rhs;
+ label_type label;
+
+ lhs.push_back(a);
+ lhs.push_back(b);
+ lhs.push_back(c);
+
+ rhs.push_back(b);
+ rhs.push_back(a);
+ rhs.push_back(c);
+
+ label.push_back(1);
+ label.push_back(0);
+ label.push_back(2);
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+
+
+
+ lhs.clear();
+ rhs.clear();
+ label.clear();
+
+ lhs.push_back(a);
+ lhs.push_back(b);
+ lhs.push_back(c);
+
+ rhs.push_back(c);
+ rhs.push_back(b);
+ rhs.push_back(a);
+ rhs.push_back(d);
+
+ label.push_back(2);
+ label.push_back(1);
+ label.push_back(0);
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+
+ lhs.clear();
+ rhs.clear();
+ label.clear();
+
+ lhs.push_back(a);
+ lhs.push_back(c);
+
+ rhs.push_back(c);
+ rhs.push_back(a);
+
+ label.push_back(1);
+ label.push_back(0);
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+
+
+
+
+ lhs.clear();
+ rhs.clear();
+ label.clear();
+
+ samples.push_back(make_pair(lhs,rhs));
+ labels.push_back(label);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename fe_type, typename F>
+ void test1(F make_data, bool force_assignment)
+ {
+ print_spinner();
+
+ std::vector<sample_type> samples;
+ std::vector<label_type> labels;
+
+ make_data(samples, labels);
+ make_data(samples, labels);
+ make_data(samples, labels);
+
+ randomize_samples(samples, labels);
+
+ structural_assignment_trainer<fe_type> trainer;
+
+ DLIB_TEST(trainer.forces_assignment() == false);
+ DLIB_TEST(trainer.get_c() == 100);
+ DLIB_TEST(trainer.get_num_threads() == 2);
+ DLIB_TEST(trainer.get_max_cache_size() == 5);
+
+
+ trainer.set_forces_assignment(force_assignment);
+ trainer.set_num_threads(3);
+ trainer.set_c(50);
+
+ DLIB_TEST(trainer.get_c() == 50);
+ DLIB_TEST(trainer.get_num_threads() == 3);
+ DLIB_TEST(trainer.forces_assignment() == force_assignment);
+
+ assignment_function<fe_type> ass = trainer.train(samples, labels);
+
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ std::vector<long> out = ass(samples[i]);
+ dlog << LINFO << "true labels: " << trans(mat(labels[i]));
+ dlog << LINFO << "pred labels: " << trans(mat(out));
+ DLIB_TEST(trans(mat(labels[i])) == trans(mat(out)));
+ }
+
+ double accuracy;
+
+ dlog << LINFO << "samples.size(): "<< samples.size();
+ accuracy = test_assignment_function(ass, samples, labels);
+ dlog << LINFO << "accuracy: "<< accuracy;
+ DLIB_TEST(accuracy == 1);
+
+ accuracy = cross_validate_assignment_trainer(trainer, samples, labels, 3);
+ dlog << LINFO << "cv accuracy: "<< accuracy;
+ DLIB_TEST(accuracy == 1);
+
+ ostringstream sout;
+ serialize(ass, sout);
+ istringstream sin(sout.str());
+ assignment_function<fe_type> ass2;
+ deserialize(ass2, sin);
+
+ DLIB_TEST(ass2.forces_assignment() == ass.forces_assignment());
+ DLIB_TEST(length(ass2.get_weights() - ass.get_weights()) < 1e-10);
+
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ std::vector<long> out = ass2(samples[i]);
+ dlog << LINFO << "true labels: " << trans(mat(labels[i]));
+ dlog << LINFO << "pred labels: " << trans(mat(out));
+ DLIB_TEST(trans(mat(labels[i])) == trans(mat(out)));
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_assignment_learning : public tester
+ {
+ public:
+ test_assignment_learning (
+ ) :
+ tester ("test_assignment_learning",
+ "Runs tests on the assignment learning code.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test1<feature_extractor_dense>(make_data, false);
+ test1<feature_extractor_sparse>(make_data, false);
+
+ test1<feature_extractor_dense>(make_data_force, false);
+ test1<feature_extractor_sparse>(make_data_force, false);
+ test1<feature_extractor_dense>(make_data_force, true);
+ test1<feature_extractor_sparse>(make_data_force, true);
+ }
+ } a;
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+
diff --git a/ml/dlib/dlib/test/base64.cpp b/ml/dlib/dlib/test/base64.cpp
new file mode 100644
index 000000000..f4d478018
--- /dev/null
+++ b/ml/dlib/dlib/test/base64.cpp
@@ -0,0 +1,208 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/base64.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.base64");
+
+ template <
+ typename base64
+ >
+ void base64_kernel_test (
+ )
+ /*!
+ requires
+ - base64 is an implementation of base64/base64_kernel_abstract.h
+ ensures
+ - runs tests on base64 for compliance with the specs
+ !*/
+ {
+
+ const unsigned int seed = static_cast<unsigned int>(time(0));
+ try
+ {
+
+ srand(seed);
+
+ base64 test;
+
+ const string wiki_normal = "\
+Man is distinguished, not only by his reason, but by this singular passion from other \
+animals, which is a lust of the mind, that by a perseverance of delight in the continued \
+and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";
+
+ const string wiki_encoded = "\
+TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0\n\
+aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1\n\
+c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0\n\
+aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl\n\
+LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=";
+
+
+
+ string str;
+
+ istringstream sin;
+ ostringstream sout;
+
+ sin.str(wiki_encoded);
+ test.decode(sin,sout);
+ DLIB_TEST_MSG(sout.str() == wiki_normal,
+ "sout.str(): " << sout.str() <<
+ "\nwiki_normal: " << wiki_normal);
+
+
+ sout.str("");
+ sin.str(wiki_normal);
+ sin.clear();
+ test.encode(sin,sout);
+
+ string a(sout.str()), b(wiki_encoded);
+ // we want to strip all the whitespace from a and b now
+ sin.str(a);
+ a.clear();
+ sin >> str;
+ while (sin)
+ {
+ a += str;
+ sin >> str;
+ }
+
+ sin.clear();
+ sin.str(b);
+ b.clear();
+ sin >> str;
+ while (sin)
+ {
+ b += str;
+ sin >> str;
+ }
+ sin.clear();
+
+ DLIB_TEST_MSG(a == b,
+ "a: \n" << a <<
+ "\n\nb: \n" << b);
+
+
+
+ sin.clear();
+ sin.str("");
+ sout.str("");
+ test.encode(sin,sout);
+ sin.str(sout.str());
+ sout.str("");
+ test.decode(sin,sout);
+ DLIB_TEST(sout.str() == "");
+
+ sin.clear();
+ sin.str("a");
+ sout.str("");
+ test.encode(sin,sout);
+ sin.str(sout.str());
+ sout.str("");
+ test.decode(sin,sout);
+ DLIB_TEST(sout.str() == "a");
+
+ sin.clear();
+ sin.str("da");
+ sout.str("");
+ test.encode(sin,sout);
+ sin.str(sout.str());
+ sout.str("");
+ test.decode(sin,sout);
+ DLIB_TEST(sout.str() == "da");
+
+ sin.clear();
+ sin.str("dav");
+ sout.str("");
+ test.encode(sin,sout);
+ sin.str(sout.str());
+ sout.str("");
+ test.decode(sin,sout);
+ DLIB_TEST(sout.str() == "dav");
+
+ sin.clear();
+ sin.str("davi");
+ sout.str("");
+ test.encode(sin,sout);
+ sin.str(sout.str());
+ sout.str("");
+ test.decode(sin,sout);
+ DLIB_TEST(sout.str() == "davi");
+
+
+ for (int i = 0; i < 1000; ++i)
+ {
+ str.clear();
+ sin.clear();
+ sout.str("");
+ sin.str("");
+
+ // fill str with random garbage
+ const int size = rand()%2000;
+ for (int j = 0; j < size; ++j)
+ {
+ unsigned char ch = rand()&0xFF;
+ str += ch;
+ }
+
+ sin.str(str);
+ test.encode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+ test.decode(sin,sout);
+
+ DLIB_TEST(str == sout.str());
+
+
+ }
+
+
+
+
+ }
+ catch (typename base64::decode_error& e)
+ {
+ DLIB_TEST_MSG(false,
+ "decode_error thrown when it shouldn't have been (" << seed << "):\n "
+ << e.info);
+ }
+ }
+
+
+ class base64_tester : public tester
+ {
+ public:
+ base64_tester (
+ ) :
+ tester ("test_base64",
+ "Runs tests on the base64 component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ base64_kernel_test<base64>();
+ }
+ } a;
+
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/bayes_nets.cpp b/ml/dlib/dlib/test/bayes_nets.cpp
new file mode 100644
index 000000000..1a3035762
--- /dev/null
+++ b/ml/dlib/dlib/test/bayes_nets.cpp
@@ -0,0 +1,411 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include "dlib/graph_utils.h"
+#include "dlib/graph.h"
+#include "dlib/directed_graph.h"
+#include "dlib/bayes_utils.h"
+#include "dlib/set.h"
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.bayes_nets");
+ enum nodes
+ {
+ A, T, S, L, O, B, D, X
+ };
+
+ template <typename gtype>
+ void setup_simple_network (
+ gtype& bn
+ )
+ {
+ /*
+ A
+ / \
+ T S
+ */
+
+ using namespace bayes_node_utils;
+
+ bn.set_number_of_nodes(3);
+ bn.add_edge(A, T);
+ bn.add_edge(A, S);
+
+
+ set_node_num_values(bn, A, 2);
+ set_node_num_values(bn, T, 2);
+ set_node_num_values(bn, S, 2);
+
+ assignment parents;
+
+ // set probabilities for node A
+ set_node_probability(bn, A, 1, parents, 0.1);
+ set_node_probability(bn, A, 0, parents, 1-0.1);
+
+ // set probabilities for node T
+ parents.add(A, 1);
+ set_node_probability(bn, T, 1, parents, 0.5);
+ set_node_probability(bn, T, 0, parents, 1-0.5);
+ parents[A] = 0;
+ set_node_probability(bn, T, 1, parents, 0.5);
+ set_node_probability(bn, T, 0, parents, 1-0.5);
+
+ // set probabilities for node S
+ parents[A] = 1;
+ set_node_probability(bn, S, 1, parents, 0.5);
+ set_node_probability(bn, S, 0, parents, 1-0.5);
+ parents[A] = 0;
+ set_node_probability(bn, S, 1, parents, 0.5);
+ set_node_probability(bn, S, 0, parents, 1-0.5);
+
+
+ // test the serialization code here by pushing this network though it
+ ostringstream sout;
+ serialize(bn, sout);
+ bn.clear();
+ DLIB_TEST(bn.number_of_nodes() == 0);
+ istringstream sin(sout.str());
+ deserialize(bn, sin);
+ DLIB_TEST(bn.number_of_nodes() == 3);
+ }
+
+
+ template <typename gtype>
+ void setup_dyspnea_network (
+ gtype& bn,
+ bool deterministic_o_node = true
+ )
+ {
+ /*
+ This is the example network used by David Zaret in his
+ reasoning under uncertainty class at Johns Hopkins
+ */
+
+ using namespace bayes_node_utils;
+
+ bn.set_number_of_nodes(8);
+ bn.add_edge(A, T);
+ bn.add_edge(T, O);
+
+ bn.add_edge(O, D);
+ bn.add_edge(O, X);
+
+ bn.add_edge(S, B);
+ bn.add_edge(S, L);
+
+ bn.add_edge(L, O);
+ bn.add_edge(B, D);
+
+
+ set_node_num_values(bn, A, 2);
+ set_node_num_values(bn, T, 2);
+ set_node_num_values(bn, O, 2);
+ set_node_num_values(bn, X, 2);
+ set_node_num_values(bn, L, 2);
+ set_node_num_values(bn, S, 2);
+ set_node_num_values(bn, B, 2);
+ set_node_num_values(bn, D, 2);
+
+ assignment parents;
+
+ // set probabilities for node A
+ set_node_probability(bn, A, 1, parents, 0.01);
+ set_node_probability(bn, A, 0, parents, 1-0.01);
+
+ // set probabilities for node S
+ set_node_probability(bn, S, 1, parents, 0.5);
+ set_node_probability(bn, S, 0, parents, 1-0.5);
+
+ // set probabilities for node T
+ parents.add(A, 1);
+ set_node_probability(bn, T, 1, parents, 0.05);
+ set_node_probability(bn, T, 0, parents, 1-0.05);
+ parents[A] = 0;
+ set_node_probability(bn, T, 1, parents, 0.01);
+ set_node_probability(bn, T, 0, parents, 1-0.01);
+
+ // set probabilities for node L
+ parents.clear();
+ parents.add(S,1);
+ set_node_probability(bn, L, 1, parents, 0.1);
+ set_node_probability(bn, L, 0, parents, 1-0.1);
+ parents[S] = 0;
+ set_node_probability(bn, L, 1, parents, 0.01);
+ set_node_probability(bn, L, 0, parents, 1-0.01);
+
+
+ // set probabilities for node B
+ parents[S] = 1;
+ set_node_probability(bn, B, 1, parents, 0.6);
+ set_node_probability(bn, B, 0, parents, 1-0.6);
+ parents[S] = 0;
+ set_node_probability(bn, B, 1, parents, 0.3);
+ set_node_probability(bn, B, 0, parents, 1-0.3);
+
+
+ // set probabilities for node O
+ double v;
+ if (deterministic_o_node)
+ v = 1;
+ else
+ v = 0.99;
+
+ parents.clear();
+ parents.add(T,1);
+ parents.add(L,1);
+ set_node_probability(bn, O, 1, parents, v);
+ set_node_probability(bn, O, 0, parents, 1-v);
+ parents[T] = 0; parents[L] = 1;
+ set_node_probability(bn, O, 1, parents, v);
+ set_node_probability(bn, O, 0, parents, 1-v);
+ parents[T] = 1; parents[L] = 0;
+ set_node_probability(bn, O, 1, parents, v);
+ set_node_probability(bn, O, 0, parents, 1-v);
+ parents[T] = 0; parents[L] = 0;
+ set_node_probability(bn, O, 1, parents, 1-v);
+ set_node_probability(bn, O, 0, parents, v);
+
+
+ // set probabilities for node D
+ parents.clear();
+ parents.add(O,1);
+ parents.add(B,1);
+ set_node_probability(bn, D, 1, parents, 0.9);
+ set_node_probability(bn, D, 0, parents, 1-0.9);
+ parents[O] = 1; parents[B] = 0;
+ set_node_probability(bn, D, 1, parents, 0.7);
+ set_node_probability(bn, D, 0, parents, 1-0.7);
+ parents[O] = 0; parents[B] = 1;
+ set_node_probability(bn, D, 1, parents, 0.8);
+ set_node_probability(bn, D, 0, parents, 1-0.8);
+ parents[O] = 0; parents[B] = 0;
+ set_node_probability(bn, D, 1, parents, 0.1);
+ set_node_probability(bn, D, 0, parents, 1-0.1);
+
+
+ // set probabilities for node X
+ parents.clear();
+ parents.add(O,1);
+ set_node_probability(bn, X, 1, parents, 0.98);
+ set_node_probability(bn, X, 0, parents, 1-0.98);
+ parents[O] = 0;
+ set_node_probability(bn, X, 1, parents, 0.05);
+ set_node_probability(bn, X, 0, parents, 1-0.05);
+
+
+ // test the serialization code here by pushing this network though it
+ ostringstream sout;
+ serialize(bn, sout);
+ bn.clear();
+ DLIB_TEST(bn.number_of_nodes() == 0);
+ istringstream sin(sout.str());
+ deserialize(bn, sin);
+ DLIB_TEST(bn.number_of_nodes() == 8);
+ }
+
+
+ void bayes_nets_test (
+ )
+ /*!
+ ensures
+ - runs tests on the bayesian network objects and functions for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ directed_graph<bayes_node>::kernel_1a_c bn;
+ setup_dyspnea_network(bn);
+
+ using namespace bayes_node_utils;
+
+
+ graph<dlib::set<unsigned long>::compare_1b_c, dlib::set<unsigned long>::compare_1b_c>::kernel_1a_c join_tree;
+
+ create_moral_graph(bn, join_tree);
+ create_join_tree(join_tree, join_tree);
+
+ bayesian_network_join_tree solution(bn, join_tree);
+
+ matrix<double,1,2> dist;
+
+ dist = solution.probability(A);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.01 ) < 1e-5);
+
+ dist = solution.probability(T);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.0104) < 1e-5);
+
+ dist = solution.probability(O);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.064828) < 1e-5);
+
+ dist = solution.probability(X);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.11029004) < 1e-5);
+
+ dist = solution.probability(L);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.055) < 1e-5);
+
+ dist = solution.probability(S);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.5) < 1e-5);
+
+ dist = solution.probability(B);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.4499999) < 1e-5);
+
+ dist = solution.probability(D);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.4359706 ) < 1e-5);
+
+ // now lets modify the probabilities of the bayesian network by making O
+ // not a deterministic node anymore but otherwise leave the network alone
+ setup_dyspnea_network(bn, false);
+
+ set_node_value(bn, A, 1);
+ set_node_value(bn, X, 1);
+ set_node_value(bn, S, 1);
+ // lets also make some of these nodes evidence nodes
+ set_node_as_evidence(bn, A);
+ set_node_as_evidence(bn, X);
+ set_node_as_evidence(bn, S);
+
+ // reload the solution now that we have changed the probabilities of node O
+ bayesian_network_join_tree(bn, join_tree).swap(solution);
+ DLIB_TEST(solution.number_of_nodes() == bn.number_of_nodes());
+
+ dist = solution.probability(A);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 1.0 ) < 1e-5);
+
+ dist = solution.probability(T);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.253508694039 ) < 1e-5);
+
+ dist = solution.probability(O);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.77856184024 ) < 1e-5);
+
+ dist = solution.probability(X);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 1.0 ) < 1e-5);
+
+ dist = solution.probability(L);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.5070173880 ) < 1e-5);
+
+ dist = solution.probability(S);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 1.0 ) < 1e-5);
+
+ dist = solution.probability(B);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.6 ) < 1e-5);
+
+ dist = solution.probability(D);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.7535685520 ) < 1e-5);
+
+
+ // now lets test the bayesian_network_gibbs_sampler
+ set_node_value(bn, A, 1);
+ set_node_value(bn, T, 1);
+ set_node_value(bn, O, 1);
+ set_node_value(bn, X, 1);
+ set_node_value(bn, S, 1);
+ set_node_value(bn, L, 1);
+ set_node_value(bn, B, 1);
+ set_node_value(bn, D, 1);
+
+ bayesian_network_gibbs_sampler sampler;
+ matrix<double,1,8> counts;
+ set_all_elements(counts, 0);
+ const unsigned long rounds = 500000;
+ for (unsigned long i = 0; i < rounds; ++i)
+ {
+ sampler.sample_graph(bn);
+
+ for (long c = 0; c < counts.nc(); ++c)
+ {
+ if (node_value(bn, c) == 1)
+ counts(c) += 1;
+ }
+
+ if ((i&0x3FF) == 0)
+ {
+ print_spinner();
+ }
+ }
+
+ counts /= rounds;
+
+ DLIB_TEST(abs(counts(A) - 1.0 ) < 1e-2);
+ DLIB_TEST(abs(counts(T) - 0.253508694039 ) < 1e-2);
+ DLIB_TEST_MSG(abs(counts(O) - 0.77856184024 ) < 1e-2,abs(counts(O) - 0.77856184024 ) );
+ DLIB_TEST(abs(counts(X) - 1.0 ) < 1e-2);
+ DLIB_TEST(abs(counts(L) - 0.5070173880 ) < 1e-2);
+ DLIB_TEST(abs(counts(S) - 1.0 ) < 1e-2);
+ DLIB_TEST(abs(counts(B) - 0.6 ) < 1e-2);
+ DLIB_TEST(abs(counts(D) - 0.7535685520 ) < 1e-2);
+
+
+ setup_simple_network(bn);
+ create_moral_graph(bn, join_tree);
+ create_join_tree(join_tree, join_tree);
+ bayesian_network_join_tree(bn, join_tree).swap(solution);
+ DLIB_TEST(solution.number_of_nodes() == bn.number_of_nodes());
+
+ dist = solution.probability(A);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.1 ) < 1e-5);
+
+ dist = solution.probability(T);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.5 ) < 1e-5);
+
+ dist = solution.probability(S);
+ DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5);
+ DLIB_TEST(abs(dist(1) - 0.5 ) < 1e-5);
+
+
+ }
+
+
+
+
+ class bayes_nets_tester : public tester
+ {
+ public:
+ bayes_nets_tester (
+ ) :
+ tester ("test_bayes_nets",
+ "Runs tests on the bayes_nets objects and functions.")
+ {}
+
+ void perform_test (
+ )
+ {
+ bayes_nets_test();
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/bigint.cpp b/ml/dlib/dlib/test/bigint.cpp
new file mode 100644
index 000000000..3ddc631b4
--- /dev/null
+++ b/ml/dlib/dlib/test/bigint.cpp
@@ -0,0 +1,522 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+
+#include <dlib/bigint.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.bigint");
+
+ namespace bigint_kernel_test_helpers
+ {
+ template <
+ typename bint
+ >
+ bint short_fact (unsigned short value)
+ /*!
+ ensures
+ - returns the factorial of value
+ !*/
+ {
+ using namespace relational_operators;
+
+ bint a = 1;
+ for (unsigned short i = 2; i <= value; ++i)
+ a *= i;
+
+ return a;
+ }
+
+ template <
+ typename bint
+ >
+ bint short_fact_squared (unsigned short value)
+ /*!
+ ensures
+ - returns the square of the factorial of value
+ !*/
+ {
+ using namespace relational_operators;
+
+ bint a = 1;
+ for (unsigned short i = 2; i <= value; ++i)
+ {
+ a *= i;
+ a *= i;
+ }
+
+ return a;
+ }
+
+
+ template <
+ typename bint
+ >
+ bint big_fact (unsigned short value)
+ /*!
+ ensures
+ - returns the factorial of value
+ !*/
+ {
+ using namespace relational_operators;
+
+ bint a = 1;
+ int k = 0;
+ for (bint i = 2; i <= value; ++i)
+ {
+ ++k;
+ if (k%10 == 0)
+ print_spinner();
+ a *= i;
+ }
+
+ return a;
+ }
+ }
+
+ template <
+ typename bint
+ >
+ void bigint_kernel_test (
+ )
+ /*!
+ requires
+ - bint is an implementation of bigint/bigint_kernel_abstract.h
+ ensures
+ - runs tests on bint for compliance with the specs
+ !*/
+ {
+ using namespace bigint_kernel_test_helpers;
+ using namespace relational_operators;
+ istringstream sin;
+ ostringstream sout;
+
+ bint i = 0;
+ bint a(5), b, c(0);
+
+ DLIB_TEST(5 - a == 0);
+ DLIB_TEST(a - 5 == 0);
+
+ DLIB_TEST(0 - c == 0);
+ DLIB_TEST(c - 0 == 0);
+
+ DLIB_TEST(0 + c == 0);
+ DLIB_TEST(c + 0 == 0);
+
+ DLIB_TEST(0 + a == 5);
+ DLIB_TEST(a + 0 == 5);
+
+ DLIB_TEST(0 - b == 0);
+ DLIB_TEST(b - 0 == 0);
+
+ DLIB_TEST(0 + b == 0);
+ DLIB_TEST(b + 0 == 0);
+
+ DLIB_TEST(i == 0);
+ DLIB_TEST(a == 5);
+ DLIB_TEST(b == 0);
+ DLIB_TEST(c == 0);
+
+
+
+ a -= 5;
+ DLIB_TEST(a == 0);
+
+
+
+ for (int k = 0; k < 100; ++k)
+ {
+ // compute the factorial of k using the O(n) multiplication algorithm
+ a = short_fact<bint>(k);
+ // compute the factorial of k using the full blown big int
+ // multiplication algorithm.
+ b = big_fact<bint>(k);
+ // compute the square of the factorial of k using the full blown
+ // big int multiplication algorithm.
+ c = a*b;
+ // make sure a and b ended up being the same number
+ DLIB_TEST_MSG(a == b,
+ "k: " << k << "\n"
+ "short_fact: " << a << "\n"
+ "big_fact: " << b
+ );
+ // make sure c really is the square of the factorial of k
+ DLIB_TEST_MSG(short_fact_squared<bint>(k) == c,"k: " << k);
+ print_spinner();
+ }
+
+ // do the same thing as the last loop but do it with way bigger numbers
+ for (int k = 1000; k < 10000; k += 2000)
+ {
+ bint a = short_fact<bint>(k);
+ bint b = big_fact<bint>(k);
+ bint c = a*b;
+ DLIB_TEST_MSG(a == b,
+ "k: " << k << "\n"
+ "short_fact: " << a << "\n"
+ "big_fact: " << b
+ );
+ DLIB_TEST_MSG(short_fact_squared<bint>(k) == c,"k: " << k);
+ print_spinner();
+ }
+
+
+
+ // test the << and >> operators a little
+ a = big_fact<bint>(20);
+ sout << a;
+ DLIB_TEST_MSG( sout.str() == "2432902008176640000","was: " << a);
+
+ sin.str("684626312793279327952039475203945");
+ sin >> a;
+ sout.str("");
+ sout << a;
+ DLIB_TEST(sout.str() == "684626312793279327952039475203945");
+
+ print_spinner();
+
+ DLIB_TEST(a > 0);
+
+
+ // make sure that when you try to read something that isn't a number
+ // into a bigint you get an error
+ DLIB_TEST(sin.fail() == false);
+ sin.str("the cat ate some cheese");
+ sin >> a;
+ DLIB_TEST(sin.fail() == true);
+ sin.clear();
+ sin.str("");
+
+
+
+ sin.str("3628913");
+ sin >> i;
+ DLIB_TEST(short_fact<bint>(10) + short_fact<bint>(5) - 7 == i);
+
+ sin.str("2432902008173011193");
+ sin >> i;
+ DLIB_TEST(short_fact<bint>(20) - short_fact<bint>(10) - 7 == i);
+
+ // test the serialization stuff
+ sout.str("");
+ serialize(i,sout);
+ i = 0;
+ sin.str(sout.str());
+ deserialize(i,sin);
+
+ DLIB_TEST(short_fact<bint>(20) - short_fact<bint>(10) - 7 == i);
+
+
+
+
+ print_spinner();
+
+
+
+
+ sin.str("100000");
+ sin >> b;
+ a = b;
+ ++b;
+ DLIB_TEST_MSG ( a + 1 == b,"a==" << a << endl << "b==" << b << endl);
+
+
+
+
+
+ // compute some stuff and see if you get the right value
+ a = 0;
+ b = 0;
+ sin.str("1000000");
+ sin >> b;
+ int mel = 0;
+ for (i = a; i <= b; ++i)
+ {
+ // switch it up on em
+ if (i%2 == 0)
+ a = a + i;
+ else
+ a += i;
+ ++mel;
+ if ((mel&0xFFF) == 0)
+ print_spinner();
+ }
+ DLIB_TEST_MSG(a == b*(b+1)/2, "a==" << a << endl << "b*(b+1)/2==" << b*(b+1)/2 << endl);
+
+
+
+
+
+
+ print_spinner();
+
+
+ // compute some stuff and see if you get the right value
+ // this time going the other way using operator--
+ a = 0;
+ b = 0;
+ sin.str("100000");
+ sin >> b;
+ i = b;
+ DLIB_TEST(i == b);
+ DLIB_TEST_MSG(i > 0,"i==" << i);
+ mel = 0;
+ for (i = b; i > 0; --i)
+ {
+ // switch it up on em
+ if (i%2 == 0)
+ a = a + i;
+ else
+ a += i;
+ ++mel;
+ if ((mel&0xFF) == 0)
+ print_spinner();
+ }
+ DLIB_TEST_MSG(a == b*(b+1)/2, "a==" << a << endl << "b*(b+1)/2==" << b*(b+1)/2 << endl);
+
+
+
+
+
+
+
+
+
+
+
+ DLIB_TEST(short_fact<bint>(10)/short_fact<bint>(5) == 30240);
+ DLIB_TEST(short_fact<bint>(10)/(short_fact<bint>(5)+1) == 29990);
+
+ sin.str("221172909834240000");
+ sin >> a;
+ DLIB_TEST(short_fact<bint>(20)/(short_fact<bint>(5)+1) == a/11);
+
+ sin.str("670442388044");
+ sin >> b;
+ DLIB_TEST(short_fact<bint>(20)/(short_fact<bint>(10)+1) == b);
+
+ print_spinner();
+
+ sin.str("1860479");
+ sin >> i;
+ DLIB_TEST_MSG(short_fact<bint>(20)/(short_fact<bint>(15)+1) == i,short_fact<bint>(20)/(short_fact<bint>(15)+1));
+
+ // test the serialization stuff
+ sout.str("");
+ serialize(i,sout);
+ i = 0;
+ sin.str(sout.str());
+ deserialize(i,sin);
+
+ DLIB_TEST_MSG(short_fact<bint>(20)/(short_fact<bint>(15)+1) == i,short_fact<bint>(20)/(short_fact<bint>(15)+1));
+
+
+ print_spinner();
+
+ // test the serialization stuff
+ sout.str("");
+ i = 0;
+ serialize(i,sout);
+ i = 1234;
+ sin.str(sout.str());
+ deserialize(i,sin);
+ DLIB_TEST(i == 0);
+
+
+ DLIB_TEST(short_fact<bint>(10000)/short_fact<bint>(9999) == 10000);
+
+
+ DLIB_TEST(bint(5)%bint(1) == 0);
+ DLIB_TEST(bint(5)%bint(6) == 5);
+ DLIB_TEST(bint(25)%bint(6) == 1);
+ print_spinner();
+ DLIB_TEST(bint(354)%bint(123) == 108);
+ DLIB_TEST(bint(20)%(bint(10)) == 0);
+ DLIB_TEST(bint(20)%(bint(10)+1) == 9);
+
+ DLIB_TEST(bint(20)%(bint(15)+1) == 4);
+
+
+ DLIB_TEST(short_fact<bint>(10)%(short_fact<bint>(5)+2) == 32);
+
+ sin.str("2908082");
+ sin >> i;
+ DLIB_TEST(short_fact<bint>(15)%(short_fact<bint>(10)+2) == i);
+
+
+
+
+
+
+ // same as some of the above stuff but using big_fact
+
+ DLIB_TEST(big_fact<bint>(10)%(big_fact<bint>(5)+2) == 32);
+
+ sin.str("2908082");
+ sin >> i;
+ DLIB_TEST(big_fact<bint>(15)%(big_fact<bint>(10)+2) == i);
+
+
+ print_spinner();
+
+
+ DLIB_TEST(big_fact<bint>(10)/big_fact<bint>(5) == 30240);
+ DLIB_TEST(big_fact<bint>(10)/(big_fact<bint>(5)+1) == 29990);
+
+ sin.str("221172909834240000");
+ sin >> a;
+ DLIB_TEST(big_fact<bint>(20)/(big_fact<bint>(5)+1) == a/11);
+
+
+ sin.str("670442388044");
+ sin >> b;
+ DLIB_TEST(big_fact<bint>(20)/(big_fact<bint>(10)+1) == b);
+
+
+ sin.str("1860479");
+ sin >> i;
+ DLIB_TEST_MSG(big_fact<bint>(20)/(big_fact<bint>(15)+1) == i,big_fact<bint>(20)/(big_fact<bint>(15)+1));
+
+ DLIB_TEST(big_fact<bint>(100)/big_fact<bint>(99) == 100);
+
+
+
+
+ sout.str("");
+ sout << "148571596448176149730952273362082573788556996128468876694221686370498539309";
+ sout << "4065876545992131370884059645617234469978112000000000000000000000";
+ sin.str(sout.str());
+ sin >> a;
+
+ sout.str("");
+ sout << "933262154439441526816992388562667004907159682643816214685929638952175999932";
+ sout << "299156089414639761565182862536979208272237582511852109168640000000000000000";
+ sout << "000000";
+ sin.str(sout.str());
+ sin >> b;
+
+
+ sout.str("");
+ sout << "138656248189732152054159609718432247180282092567575172939636909224427929240";
+ sout << "834642263988043338170905744175653189424779336521852536242160190545537133916";
+ sout << "649622615351174407746524657461692702500613722228638559932561661493048332720";
+ sout << "6050692647868232055316807680000000000000000000000000000000000000000000";
+ sin.str(sout.str());
+ sin >> c;
+
+ DLIB_TEST_MSG(a*b == c,
+ "a*b: " << a*b <<
+ "\nc: " << c);
+
+
+ print_spinner();
+
+ i = 0;
+ mel = 0;
+ unsigned long j;
+ for (j = 0; i < bint(100000); ++j)
+ {
+ DLIB_TEST(i++ == bint(j));
+ ++mel;
+ if((mel&0xFF) == 0)
+ print_spinner();
+ }
+ DLIB_TEST(j == 100000);
+
+ i = 1234;
+
+ DLIB_TEST(i == 1234);
+ DLIB_TEST(i < 2345 );
+ DLIB_TEST(i > 0 );
+ DLIB_TEST(i > 123 );
+
+ DLIB_TEST(i != 1334);
+ DLIB_TEST(i <= 2345);
+ DLIB_TEST(i >= 0 );
+ DLIB_TEST(i >= 123 );
+ DLIB_TEST(i >= 1234);
+ DLIB_TEST(i <= 1234);
+
+
+ DLIB_TEST(1234 == i);
+ DLIB_TEST(2345 > i);
+ DLIB_TEST(0 < i);
+ DLIB_TEST(123 < i);
+
+ DLIB_TEST(1334 != i);
+ DLIB_TEST(2345 >= i);
+ DLIB_TEST(0 <= i);
+ DLIB_TEST(123 <= i);
+ DLIB_TEST(1234 <= i);
+ DLIB_TEST(1234 >= i);
+
+
+ a = big_fact<bint>(200);
+ b = big_fact<bint>(100);
+
+ DLIB_TEST(a > b);
+ DLIB_TEST(a != b);
+ DLIB_TEST(b < a);
+ DLIB_TEST(b != a);
+ DLIB_TEST(b <= a);
+ DLIB_TEST(a >= b);
+
+
+
+ a = 10000;
+ a = a*a*a*a; a = a*a; a = a*a;
+ b = 2;
+ DLIB_TEST((a/b)*b == a);
+
+ a = 10000*5;
+ a = a*a*a*a; a = a*a; a = a*a;
+ b = 5;
+ DLIB_TEST((a/b)*b == a);
+ }
+
+
+
+
+ class bigint_tester : public tester
+ {
+ public:
+ bigint_tester (
+ ) :
+ tester ("test_bigint",
+ "Runs tests on the bigint component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ bigint_kernel_test<bigint::kernel_1a>();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_1a_c";
+ bigint_kernel_test<bigint::kernel_1a_c>();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_2a";
+ bigint_kernel_test<bigint::kernel_2a>();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_2a_c";
+ bigint_kernel_test<bigint::kernel_2a_c>();
+ print_spinner();
+
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/binary_search_tree.h b/ml/dlib/dlib/test/binary_search_tree.h
new file mode 100644
index 000000000..18bdff70d
--- /dev/null
+++ b/ml/dlib/dlib/test/binary_search_tree.h
@@ -0,0 +1,889 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_
+#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/memory_manager_global.h>
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/binary_search_tree.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.binary_search_tree");
+
+ template <
+ typename bst
+ >
+ void binary_search_tree_kernel_test (
+ )
+ /*!
+ requires
+ - bst is an implementation of
+ binary_search_tree/binary_search_tree_kernel_abstract.h is instantiated
+ to map int to int
+ ensures
+ - runs tests on bst for compliance with the specs
+ !*/
+ {
+
+ bst test, test2;
+
+ srand(static_cast<unsigned int>(time(0)));
+
+
+ DLIB_TEST(test.count(3) == 0);
+
+ enumerable<map_pair<int,int> >& e = test;
+ DLIB_TEST(e.at_start() == true);
+
+ DLIB_TEST(test.count(3) == 0);
+
+ for (int i = 0; i < 4; ++i)
+ {
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.count(3) == 0);
+ DLIB_TEST(test.height() == 0);
+ DLIB_TEST(test[5] == 0);
+ DLIB_TEST(test[0] == 0);
+ DLIB_TEST(test.at_start());
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.count(3) == 0);
+
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.count(3) == 0);
+
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ test.clear();
+ test.position_enumerator(5);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ test.position_enumerator(5);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ test.position_enumerator(9);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ test.clear();
+ test.position_enumerator(5);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ test.position_enumerator(5);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ test.position_enumerator(9);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ test.clear();
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ DLIB_TEST(test.count(3) == 0);
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.height() == 0);
+ DLIB_TEST(test[5] == 0);
+ DLIB_TEST(test[0] == 0);
+ DLIB_TEST(const_cast<const bst&>(test)[5] == 0);
+ DLIB_TEST(const_cast<const bst&>(test)[0] == 0);
+ DLIB_TEST(test.at_start());
+ DLIB_TEST(test.current_element_valid() == false);
+
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ DLIB_TEST(test.count(3) == 0);
+ test.reset();
+ DLIB_TEST(test.count(3) == 0);
+
+ DLIB_TEST(test.at_start());
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+
+
+
+
+ int a = 0, b = 0;
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand()%1000;
+ int temp = a;
+ unsigned long count = test.count(a);
+ test.add(a,b);
+ DLIB_TEST(test.count(temp) == count+1);
+ }
+
+
+ {
+ unsigned long count = test.count(3);
+
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ }
+
+
+ test.clear();
+
+
+
+
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand()&0x7FFF;
+ b = 0;
+ int temp = a;
+ unsigned long count = test.count(a);
+ test.add(a,b);
+ DLIB_TEST(test.count(temp) == count+1);
+ }
+
+ // serialize the state of test, then clear test, then
+ // load the state back into test.
+ ostringstream sout;
+ serialize(test,sout);
+ istringstream sin(sout.str());
+ test.clear();
+ deserialize(test,sin);
+
+ DLIB_TEST(test.size() == 10000);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ DLIB_TEST_MSG(test.height() > 13 && test.height() <= 26,"this is somewhat of an implementation dependent "
+ << "but really it should be in this range or the implementation is just crap");
+
+ a = 0;
+ unsigned long count = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST_MSG(a <= test.element().key(),"the numers are out of order but they should be in order");
+ a = test.element().key();
+ ++count;
+
+
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+
+ DLIB_TEST(count == 10000);
+
+
+
+
+ DLIB_TEST_MSG(test.height() > 13 && test.height() <= 26,"this is somewhat of an implementation dependent "
+ << "but really it should be in this range or the implementation is just crap");
+
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.size() == 10000);
+
+
+ swap(test,test2);
+
+
+ test2.reset();
+ count = 0;
+ a = 0;
+ while (test2.move_next())
+ {
+ DLIB_TEST_MSG(a <= test2.element().key(),"the numers are out of order but they should be in order");
+ a = test2.element().key();
+ ++count;
+
+
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == true);
+
+ if (count == 5000)
+ {
+ break;
+ }
+ }
+
+ DLIB_TEST(test2.move_next() == true);
+ DLIB_TEST(test2.move_next() == true);
+ DLIB_TEST(test2.move_next() == true);
+
+
+ test2.reset();
+
+ count = 0;
+ a = 0;
+ while (test2.move_next())
+ {
+ DLIB_TEST_MSG(a <= test2.element().key(),"the numers are out of order but they should be in order");
+ a = test2.element().key();
+ ++count;
+
+
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == true);
+ }
+
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.move_next() == false);
+
+
+
+
+
+
+
+
+ int last = 0;
+ asc_pair_remover<int,int,typename bst::compare_type>& asdf = test2;
+ DLIB_TEST(asdf.size() > 0);
+ while (asdf.size() > 0)
+ {
+ asdf.remove_any(a,b);
+ DLIB_TEST(last <= a);
+ last = a;
+ --count;
+ DLIB_TEST(asdf.size() == count);
+ }
+
+
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.height() ==0);
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.move_next() == false);
+
+
+
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = i;
+ b = i;
+ test2.add(a,b);
+ DLIB_TEST(test2.size() == (unsigned int)(i +1));
+ DLIB_TEST(test2.count(i) == 1);
+ }
+
+ a = 0;
+ test2.position_enumerator(a);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.element().key() == a);
+ DLIB_TEST(test2.element().value() == a);
+ a = 0;
+ test2.position_enumerator(a);
+ DLIB_TEST(test2.element().key() == a);
+ DLIB_TEST(test2.element().value() == a);
+ a = 8;
+ test2.position_enumerator(a);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.element().key() == a);
+ DLIB_TEST(test2.element().value() == a);
+ a = 1;
+ test2.position_enumerator(a);
+ DLIB_TEST(test2.element().key() == a);
+ DLIB_TEST(test2.element().value() == a);
+ a = -29;
+ test2.position_enumerator(a);
+ DLIB_TEST(test2.element().key() == 0);
+ DLIB_TEST(test2.element().value() == 0);
+ a = 10000;
+ test2.position_enumerator(a);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ a = -29;
+ test2.position_enumerator(a);
+ DLIB_TEST(test2.element().key() == 0);
+ DLIB_TEST(test2.element().value() == 0);
+ a = 8;
+ test2.position_enumerator(a);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.element().key() == a);
+ DLIB_TEST(test2.element().value() == a);
+ test2.reset();
+
+
+ DLIB_TEST_MSG(test2.height() > 13 && test2.height() <= 26,"this is somewhat of an implementation dependent "
+ << "but really it should be in this range or the implementation is just crap");
+
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.size() == 10000);
+
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ DLIB_TEST(test2.move_next() == true);
+ DLIB_TEST(test2.element().key() == i);
+ }
+
+
+
+ DLIB_TEST_MSG(test2.height() > 13 && test2.height() <= 26,"this is somewhat of an implementation dependent "
+ << "but really it should be in this range or the implementation is just crap");
+
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.size() == 10000);
+
+
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+
+ a = 3;
+ test2.add(a,b);
+ DLIB_TEST(test2.count(3) == 2);
+
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ test2.remove(i,a,b);
+ DLIB_TEST(i == a);
+ }
+ test2.remove(3,a,b);
+
+
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.height() == 0);
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+
+
+
+ test2.clear();
+
+
+ int m = 0;
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand()&0x7FFF;
+ m = max(a,m);
+ test2.add(a,b);
+ }
+
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.move_next() == true);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.move_next() == true);
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.move_next() == true);
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.move_next() == true);
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.at_start() == false);
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand()&0xFFFF;
+ test2.position_enumerator(a);
+ if (test2[a])
+ {
+ DLIB_TEST(test2.element().key() == a);
+ }
+ else if (a <= m)
+ {
+ DLIB_TEST(test2.element().key() > a);
+ }
+ }
+
+ test2.clear();
+
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+
+
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.height() == 0);
+
+
+ for (int i = 0; i < 20000; ++i)
+ {
+ a = ::rand()&0x7FFF;
+ b = a;
+ test2.add(a,b);
+ }
+
+
+ DLIB_TEST(test2.size() == 20000);
+
+
+
+ // remove a bunch of elements randomly
+ int c;
+ for (int i = 0; i < 50000; ++i)
+ {
+ a = ::rand()&0x7FFF;
+ if (test2[a] != 0)
+ {
+ test2.remove(a,b,c);
+ DLIB_TEST(a == b);
+ }
+ }
+
+
+ // now add a bunch more
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand()&0x7FFF;
+ b = a;
+ test2.add(a,b);
+ }
+
+
+ // now iterate over it all and then remove all elements
+ {
+ int* array = new int[test2.size()];
+ int* tmp = array;
+ DLIB_TEST(test2.at_start() == true);
+ while (test2.move_next())
+ {
+ *tmp = test2.element().key();
+ ++tmp;
+ }
+
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+
+ tmp = array;
+ for (int i = 0; i < 10000; ++i)
+ {
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ DLIB_TEST(*const_cast<const bst&>(test2)[*tmp] == *tmp);
+ ++tmp;
+ }
+
+ tmp = array;
+ while (test2.size() > 0)
+ {
+ unsigned long count = test2.count(*tmp);
+ test2.destroy(*tmp);
+ DLIB_TEST(test2.count(*tmp)+1 == count);
+ ++tmp;
+ }
+
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.at_start() == false);
+ test.swap(test2);
+ test.reset();
+
+ delete [] array;
+ }
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.height() == 0);
+
+ for (unsigned long i = 1; i < 100; ++i)
+ {
+ a = 1234;
+ test.add(a,b);
+ DLIB_TEST(test.count(1234) == i);
+ }
+
+ test.clear();
+
+
+
+
+
+
+ for (int m = 0; m < 3; ++m)
+ {
+
+ test2.clear();
+
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+
+
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.height() == 0);
+
+
+ int counter = 0;
+ while (counter < 10000)
+ {
+ a = ::rand()&0x7FFF;
+ b = ::rand()&0x7FFF;
+ if (test2[a] == 0)
+ {
+ test2.add(a,b);
+ ++counter;
+ }
+
+ }
+
+
+
+ DLIB_TEST(test2.size() == 10000);
+
+
+
+ // remove a bunch of elements randomly
+ for (int i = 0; i < 20000; ++i)
+ {
+ a = ::rand()&0x7FFF;
+ if (test2[a] != 0)
+ {
+ test2.remove(a,b,c);
+ DLIB_TEST(a == b);
+ }
+ }
+
+
+ // now add a bunch more
+ for (int i = 0; i < 20000; ++i)
+ {
+ a = ::rand()&0x7FFF;
+ b = ::rand()&0x7FFF;
+ if (test2[a] == 0)
+ test2.add(a,b);
+ }
+
+
+ // now iterate over it all and then remove all elements
+ {
+ int* array = new int[test2.size()];
+ int* array_val = new int[test2.size()];
+ int* tmp = array;
+ int* tmp_val = array_val;
+ DLIB_TEST(test2.at_start() == true);
+ int count = 0;
+ while (test2.move_next())
+ {
+ *tmp = test2.element().key();
+ ++tmp;
+ *tmp_val = test2.element().value();
+ ++tmp_val;
+
+ DLIB_TEST(*test2[*(tmp-1)] == *(tmp_val-1));
+ ++count;
+ }
+
+ DLIB_TEST(count == (int)test2.size());
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+
+ tmp = array;
+ tmp_val = array_val;
+ for (unsigned long i = 0; i < test2.size(); ++i)
+ {
+ DLIB_TEST_MSG(*test2[*tmp] == *tmp_val,i);
+ DLIB_TEST(*test2[*tmp] == *tmp_val);
+ DLIB_TEST(*test2[*tmp] == *tmp_val);
+ DLIB_TEST(*const_cast<const bst&>(test2)[*tmp] == *tmp_val);
+ ++tmp;
+ ++tmp_val;
+ }
+
+ // out << "\nsize: " << test2.size() << endl;
+ // out << "height: " << test2.height() << endl;
+
+ tmp = array;
+ while (test2.size() > 0)
+ {
+ unsigned long count = test2.count(*tmp);
+ test2.destroy(*tmp);
+ DLIB_TEST(test2.count(*tmp)+1 == count);
+ ++tmp;
+ }
+
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.at_start() == false);
+ test.swap(test2);
+ test.reset();
+
+ delete [] array;
+ delete [] array_val;
+ }
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.height() == 0);
+
+ for (unsigned long i = 1; i < 100; ++i)
+ {
+ a = 1234;
+ test.add(a,b);
+ DLIB_TEST(test.count(1234) == i);
+ }
+
+ test.clear();
+
+ }
+
+
+
+ a = 1;
+ b = 2;
+
+ test.add(a,b);
+
+ test.position_enumerator(0);
+ a = 0;
+ b = 0;
+ DLIB_TEST(test.height() == 1);
+ test.remove_current_element(a,b);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.height() == 0);
+ DLIB_TEST(test.size() == 0);
+
+
+ a = 1;
+ b = 2;
+ test.add(a,b);
+ a = 1;
+ b = 2;
+ test.add(a,b);
+
+ test.position_enumerator(0);
+ a = 0;
+ b = 0;
+ DLIB_TEST(test.height() == 2);
+ test.remove_current_element(a,b);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+ DLIB_TEST(test.height() == 1);
+ DLIB_TEST(test.size() == 1);
+
+ test.remove_current_element(a,b);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.height() == 0);
+ DLIB_TEST(test.size() == 0);
+
+ for (int i = 0; i < 100; ++i)
+ {
+ a = i;
+ b = i;
+ test.add(a,b);
+ }
+
+ DLIB_TEST(test.size() == 100);
+ test.remove_last_in_order(a,b);
+ DLIB_TEST(a == 99);
+ DLIB_TEST(b == 99);
+ DLIB_TEST(test.size() == 99);
+ test.remove_last_in_order(a,b);
+ DLIB_TEST(a == 98);
+ DLIB_TEST(b == 98);
+ DLIB_TEST(test.size() == 98);
+
+ test.position_enumerator(-10);
+ for (int i = 0; i < 97; ++i)
+ {
+ DLIB_TEST(test.element().key() == i);
+ DLIB_TEST(test.element().value() == i);
+ DLIB_TEST(test.move_next());
+ }
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ test.position_enumerator(10);
+ for (int i = 10; i < 97; ++i)
+ {
+ DLIB_TEST(test.element().key() == i);
+ DLIB_TEST(test.element().value() == i);
+ DLIB_TEST(test.move_next());
+ }
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ test.reset();
+ DLIB_TEST(test.at_start());
+ DLIB_TEST(test.current_element_valid() == false);
+ for (int i = 0; i < 98; ++i)
+ {
+ DLIB_TEST(test.move_next());
+ DLIB_TEST(test.element().key() == i);
+ DLIB_TEST(test.element().value() == i);
+ }
+ DLIB_TEST_MSG(test.size() == 98, test.size());
+ DLIB_TEST(test.move_next() == false);
+
+ test.position_enumerator(98);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+
+
+ test.position_enumerator(50);
+ DLIB_TEST(test.element().key() == 50);
+ DLIB_TEST(test.element().value() == 50);
+ DLIB_TEST(test[50] != 0);
+ test.remove_current_element(a,b);
+ DLIB_TEST(test[50] == 0);
+ DLIB_TEST_MSG(test.size() == 97, test.size());
+ DLIB_TEST(a == 50);
+ DLIB_TEST(b == 50);
+ DLIB_TEST(test.element().key() == 51);
+ DLIB_TEST(test.element().value() == 51);
+ DLIB_TEST(test.current_element_valid());
+ test.remove_current_element(a,b);
+ DLIB_TEST_MSG(test.size() == 96, test.size());
+ DLIB_TEST(a == 51);
+ DLIB_TEST(b == 51);
+ DLIB_TEST_MSG(test.element().key() == 52,test.element().key());
+ DLIB_TEST_MSG(test.element().value() == 52,test.element().value());
+ DLIB_TEST(test.current_element_valid());
+ test.remove_current_element(a,b);
+ DLIB_TEST_MSG(test.size() == 95, test.size());
+ DLIB_TEST(a == 52);
+ DLIB_TEST(b == 52);
+ DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
+ DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
+ DLIB_TEST(test.current_element_valid());
+ test.position_enumerator(50);
+ DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
+ DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
+ DLIB_TEST(test.current_element_valid());
+ test.position_enumerator(51);
+ DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
+ DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
+ DLIB_TEST(test.current_element_valid());
+ test.position_enumerator(52);
+ DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
+ DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
+ DLIB_TEST(test.current_element_valid());
+ test.position_enumerator(53);
+ DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
+ DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
+ DLIB_TEST(test.current_element_valid());
+
+ test.reset();
+ test.move_next();
+ int lasta = -1, lastb = -1;
+ count = 0;
+ while (test.current_element_valid() )
+ {
+ ++count;
+ int c = test.element().key();
+ int d = test.element().value();
+ test.remove_current_element(a,b);
+ DLIB_TEST(c == a);
+ DLIB_TEST(d == a);
+ DLIB_TEST(lasta < a);
+ DLIB_TEST(lastb < b);
+ lasta = a;
+ lastb = b;
+ }
+ DLIB_TEST_MSG(count == 95, count);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.height() == 0);
+
+ test.clear();
+
+ for (int i = 0; i < 1000; ++i)
+ {
+ a = 1;
+ b = 1;
+ test.add(a,b);
+ }
+
+ for (int i = 0; i < 40; ++i)
+ {
+ int num = ::rand()%800 + 1;
+ test.reset();
+ for (int j = 0; j < num; ++j)
+ {
+ DLIB_TEST(test.move_next());
+ }
+ DLIB_TEST_MSG(test.current_element_valid(),"size: " << test.size() << " num: " << num);
+ test.remove_current_element(a,b);
+ DLIB_TEST_MSG(test.current_element_valid(),"size: " << test.size() << " num: " << num);
+ test.remove_current_element(a,b);
+ test.position_enumerator(1);
+ if (test.current_element_valid())
+ test.remove_current_element(a,b);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 1);
+ }
+
+ test.clear();
+
+ }
+
+
+ test.clear();
+ test2.clear();
+
+ }
+
+}
+
+#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_
+
diff --git a/ml/dlib/dlib/test/binary_search_tree_kernel_1a.cpp b/ml/dlib/dlib/test/binary_search_tree_kernel_1a.cpp
new file mode 100644
index 000000000..b7e0b3a1a
--- /dev/null
+++ b/ml/dlib/dlib/test/binary_search_tree_kernel_1a.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_
+#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/memory_manager_global.h>
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/binary_search_tree.h>
+#include "tester.h"
+#include "binary_search_tree.h"
+
+namespace
+{
+
+
+ class binary_search_tree_tester : public tester
+ {
+
+ public:
+ binary_search_tree_tester (
+ ) :
+ tester ("test_binary_search_tree_kernel_1a",
+ "Runs tests on the binary_search_tree_kernel_1a component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ binary_search_tree_kernel_test<binary_search_tree<int,int>::kernel_1a>();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_1a_c";
+ binary_search_tree_kernel_test<binary_search_tree<int,int>::kernel_1a_c>();
+ print_spinner();
+ }
+ } a;
+
+}
+
+#endif
diff --git a/ml/dlib/dlib/test/binary_search_tree_kernel_2a.cpp b/ml/dlib/dlib/test/binary_search_tree_kernel_2a.cpp
new file mode 100644
index 000000000..e2be4b143
--- /dev/null
+++ b/ml/dlib/dlib/test/binary_search_tree_kernel_2a.cpp
@@ -0,0 +1,45 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_
+#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/memory_manager_global.h>
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/binary_search_tree.h>
+#include "tester.h"
+#include "binary_search_tree.h"
+
+namespace
+{
+
+ class binary_search_tree_tester : public tester
+ {
+ public:
+ binary_search_tree_tester (
+ ) :
+ tester ("test_binary_search_tree_kernel_2a",
+ "Runs tests on the binary_search_tree_kernel_2a component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_2a";
+ binary_search_tree_kernel_test<binary_search_tree<int,int>::kernel_2a>();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_2a_c";
+ binary_search_tree_kernel_test<binary_search_tree<int,int>::kernel_2a_c>();
+ print_spinner();
+ }
+ } a;
+
+}
+
+#endif
diff --git a/ml/dlib/dlib/test/binary_search_tree_mm1.cpp b/ml/dlib/dlib/test/binary_search_tree_mm1.cpp
new file mode 100644
index 000000000..a9693bd15
--- /dev/null
+++ b/ml/dlib/dlib/test/binary_search_tree_mm1.cpp
@@ -0,0 +1,66 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_
+#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/memory_manager_global.h>
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/binary_search_tree.h>
+#include "tester.h"
+#include "binary_search_tree.h"
+
+namespace
+{
+
+ class binary_search_tree_tester : public tester
+ {
+ struct factory
+ {
+ template <typename U>
+ struct return_type {
+ typedef typename memory_manager<U>::kernel_1c type;
+ };
+
+ template <typename U>
+ static typename return_type<U>::type* get_instance (
+ )
+ {
+ static typename return_type<U>::type instance;
+ return &instance;
+ }
+
+ };
+
+
+ public:
+ binary_search_tree_tester (
+ ) :
+ tester ("test_binary_search_tree_mm1",
+ "Runs tests on the binary_search_tree component with memory managers.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a /w memory_manager_global";
+ binary_search_tree_kernel_test<binary_search_tree<int,int,
+ memory_manager_global<char,factory>::kernel_1a>::kernel_1a>();
+ print_spinner();
+
+
+ dlog << LINFO << "testing kernel_1a /w memory_manager_stateless";
+ binary_search_tree_kernel_test<binary_search_tree<int,int,
+ memory_manager_stateless<char>::kernel_1a>::kernel_1a>();
+ print_spinner();
+ }
+ } a;
+
+}
+
+#endif
diff --git a/ml/dlib/dlib/test/binary_search_tree_mm2.cpp b/ml/dlib/dlib/test/binary_search_tree_mm2.cpp
new file mode 100644
index 000000000..354b1f91c
--- /dev/null
+++ b/ml/dlib/dlib/test/binary_search_tree_mm2.cpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_
+#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/memory_manager_global.h>
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/binary_search_tree.h>
+#include "tester.h"
+#include "binary_search_tree.h"
+
+namespace
+{
+
+ class binary_search_tree_tester : public tester
+ {
+
+ public:
+ binary_search_tree_tester (
+ ) :
+ tester ("test_binary_search_tree_mm2",
+ "Runs tests on the binary_search_tree component with memory managers.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a /w memory_manager_stateless_2";
+ binary_search_tree_kernel_test<binary_search_tree<int,int,
+ memory_manager_stateless<char>::kernel_2_2c>::kernel_1a>();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_1a /w memory_manager_3";
+ binary_search_tree_kernel_test<binary_search_tree<int,int,
+ memory_manager<char>::kernel_3b>::kernel_1a>();
+ print_spinner();
+ }
+ } a;
+
+}
+
+#endif
diff --git a/ml/dlib/dlib/test/blas_bindings/CMakeLists.txt b/ml/dlib/dlib/test/blas_bindings/CMakeLists.txt
new file mode 100644
index 000000000..5deddee04
--- /dev/null
+++ b/ml/dlib/dlib/test/blas_bindings/CMakeLists.txt
@@ -0,0 +1,33 @@
+#
+# This is a CMake makefile. You can find the cmake utility and
+# information about it at http://www.cmake.org
+#
+
+cmake_minimum_required(VERSION 2.8.12)
+
+# This variable contains a list of all the tests we are building
+# into the regression test suite.
+set (tests
+ blas_bindings_gemm.cpp
+ blas_bindings_gemv.cpp
+ blas_bindings_ger.cpp
+ blas_bindings_dot.cpp
+ blas_bindings_scal_axpy.cpp
+ vector.cpp
+ )
+
+# create a variable called target_name and set it to the string "test"
+set (target_name dtest)
+
+PROJECT(${target_name})
+
+# add all the cpp files we want to compile to this list. This tells
+# cmake that they are part of our target (which is the executable named test)
+ADD_EXECUTABLE(${target_name} ../main.cpp ../tester.cpp ${tests})
+
+ADD_DEFINITIONS(-DDLIB_TEST_BLAS_BINDINGS)
+
+# Tell cmake to link our target executable to dlib
+include(../../cmake)
+TARGET_LINK_LIBRARIES(${target_name} dlib )
+
diff --git a/ml/dlib/dlib/test/blas_bindings/blas_bindings_dot.cpp b/ml/dlib/dlib/test/blas_bindings/blas_bindings_dot.cpp
new file mode 100644
index 000000000..0571b0685
--- /dev/null
+++ b/ml/dlib/dlib/test/blas_bindings/blas_bindings_dot.cpp
@@ -0,0 +1,314 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "../tester.h"
+#include <dlib/matrix.h>
+
+#ifndef DLIB_USE_BLAS
+#error "BLAS bindings must be used for this test to make any sense"
+#endif
+
+namespace dlib
+{
+ namespace blas_bindings
+ {
+ // This is a little screwy. This function is used inside the BLAS
+ // bindings to count how many times each of the BLAS functions get called.
+#ifdef DLIB_TEST_BLAS_BINDINGS
+ int& counter_dot() { static int counter = 0; return counter; }
+#endif
+
+ }
+}
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.dot");
+
+
+ class blas_bindings_dot_tester : public tester
+ {
+ public:
+ blas_bindings_dot_tester (
+ ) :
+ tester (
+ "test_dot", // the command line argument name for this test
+ "Run tests for DOT routines.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {}
+
+ void test_mat_bindings()
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+ matrix<double,1,0> rv(10);
+ matrix<double,0,1> cv(10);
+ double val;
+
+ rv = 1; cv = 1;
+ counter_dot() = 0;
+ val = rv*cv;
+ DLIB_TEST(val == 10);
+ DLIB_TEST(counter_dot() == 1);
+
+ rv = 1; cv = 1;
+ counter_dot() = 0;
+ val = rv*mat(&cv(0),cv.size());
+ DLIB_TEST(val == 10);
+ DLIB_TEST(counter_dot() == 1);
+
+ rv = 1; cv = 1;
+ counter_dot() = 0;
+ val = trans(mat(&rv(0),rv.size()))*mat(&cv(0),cv.size());
+ DLIB_TEST(val == 10);
+ DLIB_TEST(counter_dot() == 1);
+
+ std::vector<double> sv(10,1);
+ rv = 1;
+ counter_dot() = 0;
+ val = trans(mat(&rv(0),rv.size()))*mat(sv);
+ DLIB_TEST(val == 10);
+ DLIB_TEST(counter_dot() == 1);
+
+
+ counter_dot() = 0;
+ val = trans(mat(sv))*mat(sv);
+ DLIB_TEST(val == 10);
+ DLIB_TEST(counter_dot() == 1);
+
+ std_vector_c<double> svc(10,1);
+ counter_dot() = 0;
+ val = trans(mat(svc))*mat(svc);
+ DLIB_TEST(val == 10);
+ DLIB_TEST(counter_dot() == 1);
+
+
+ dlib::array<double> arr(10);
+ for (unsigned int i = 0; i < arr.size(); ++i)
+ arr[i] = 1;
+ counter_dot() = 0;
+ val = trans(mat(arr))*mat(arr);
+ DLIB_TEST(val == 10);
+ DLIB_TEST(counter_dot() == 1);
+ }
+
+ template <typename matrix_type, typename cv_type, typename rv_type>
+ void test_dot_stuff(
+ matrix_type& m,
+ rv_type& rv,
+ cv_type& cv
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ rv_type rv2;
+ cv_type cv2;
+ matrix_type m2;
+ typedef typename matrix_type::type scalar_type;
+ scalar_type val;
+
+ counter_dot() = 0;
+ m2 = rv*cv;
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = rv*cv;
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = rv*3*cv;
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = rv*trans(rv)*3;
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = trans(rv*trans(rv)*3 + trans(cv)*cv);
+ DLIB_TEST(counter_dot() == 2);
+
+
+ counter_dot() = 0;
+ val = trans(cv)*cv;
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = trans(cv)*trans(rv);
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = dot(rv,cv);
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = dot(rv,colm(cv,0));
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = dot(cv,cv);
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = dot(colm(cv,0,cv.size()),colm(cv,0));
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = dot(rv,rv);
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = dot(rv,trans(rv));
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = dot(trans(cv),cv);
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = dot(trans(cv),trans(rv));
+ DLIB_TEST(counter_dot() == 1);
+
+
+ // This does one dot and one gemv
+ counter_dot() = 0;
+ val = trans(cv)*m*trans(rv);
+ DLIB_TEST_MSG(counter_dot() == 1, counter_dot());
+
+ // This does one dot and two gemv
+ counter_dot() = 0;
+ val = (trans(cv)*m)*(m*trans(rv));
+ DLIB_TEST_MSG(counter_dot() == 1, counter_dot());
+
+ // This does one dot and two gemv
+ counter_dot() = 0;
+ val = trans(cv)*m*trans(m)*trans(rv);
+ DLIB_TEST_MSG(counter_dot() == 1, counter_dot());
+ }
+
+
+ template <typename matrix_type, typename cv_type, typename rv_type>
+ void test_dot_stuff_conj(
+ matrix_type& ,
+ rv_type& rv,
+ cv_type& cv
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ rv_type rv2;
+ cv_type cv2;
+ matrix_type m2;
+ typedef typename matrix_type::type scalar_type;
+ scalar_type val;
+
+ counter_dot() = 0;
+ val = conj(rv)*cv;
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = trans(conj(cv))*cv;
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = trans(conj(cv))*trans(rv);
+ DLIB_TEST(counter_dot() == 1);
+
+ counter_dot() = 0;
+ val = trans(conj(cv))*3*trans(rv);
+ DLIB_TEST(counter_dot() == 1);
+ }
+
+ void perform_test (
+ )
+ {
+ using namespace dlib;
+ typedef dlib::memory_manager<char>::kernel_1a mm;
+
+ dlog << dlib::LINFO << "test double";
+ {
+ matrix<double> m = randm(4,4);
+ matrix<double,1,0> rv = randm(1,4);
+ matrix<double,0,1> cv = randm(4,1);
+ test_dot_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test float";
+ {
+ matrix<float> m = matrix_cast<float>(randm(4,4));
+ matrix<float,1,0> rv = matrix_cast<float>(randm(1,4));
+ matrix<float,0,1> cv = matrix_cast<float>(randm(4,1));
+ test_dot_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<double>";
+ {
+ matrix<complex<double> > m = complex_matrix(randm(4,4), randm(4,4));
+ matrix<complex<double>,1,0> rv = complex_matrix(randm(1,4), randm(1,4));
+ matrix<complex<double>,0,1> cv = complex_matrix(randm(4,1), randm(4,1));
+ test_dot_stuff(m,rv,cv);
+ test_dot_stuff_conj(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<float>";
+ {
+ matrix<complex<float> > m = matrix_cast<complex<float> >(complex_matrix(randm(4,4), randm(4,4)));
+ matrix<complex<float>,1,0> rv = matrix_cast<complex<float> >(complex_matrix(randm(1,4), randm(1,4)));
+ matrix<complex<float>,0,1> cv = matrix_cast<complex<float> >(complex_matrix(randm(4,1), randm(4,1)));
+ test_dot_stuff(m,rv,cv);
+ test_dot_stuff_conj(m,rv,cv);
+ }
+
+
+ dlog << dlib::LINFO << "test double, column major";
+ {
+ matrix<double,0,0,mm,column_major_layout> m = randm(4,4);
+ matrix<double,1,0,mm,column_major_layout> rv = randm(1,4);
+ matrix<double,0,1,mm,column_major_layout> cv = randm(4,1);
+ test_dot_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test float, column major";
+ {
+ matrix<float,0,0,mm,column_major_layout> m = matrix_cast<float>(randm(4,4));
+ matrix<float,1,0,mm,column_major_layout> rv = matrix_cast<float>(randm(1,4));
+ matrix<float,0,1,mm,column_major_layout> cv = matrix_cast<float>(randm(4,1));
+ test_dot_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<double>, column major";
+ {
+ matrix<complex<double>,0,0,mm,column_major_layout > m = complex_matrix(randm(4,4), randm(4,4));
+ matrix<complex<double>,1,0,mm,column_major_layout> rv = complex_matrix(randm(1,4), randm(1,4));
+ matrix<complex<double>,0,1,mm,column_major_layout> cv = complex_matrix(randm(4,1), randm(4,1));
+ test_dot_stuff(m,rv,cv);
+ test_dot_stuff_conj(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<float>, column major";
+ {
+ matrix<complex<float>,0,0,mm,column_major_layout > m = matrix_cast<complex<float> >(complex_matrix(randm(4,4), randm(4,4)));
+ matrix<complex<float>,1,0,mm,column_major_layout> rv = matrix_cast<complex<float> >(complex_matrix(randm(1,4), randm(1,4)));
+ matrix<complex<float>,0,1,mm,column_major_layout> cv = matrix_cast<complex<float> >(complex_matrix(randm(4,1), randm(4,1)));
+ test_dot_stuff(m,rv,cv);
+ test_dot_stuff_conj(m,rv,cv);
+ }
+
+
+ test_mat_bindings();
+
+ print_spinner();
+ }
+ };
+
+ blas_bindings_dot_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/blas_bindings/blas_bindings_gemm.cpp b/ml/dlib/dlib/test/blas_bindings/blas_bindings_gemm.cpp
new file mode 100644
index 000000000..83d41edd1
--- /dev/null
+++ b/ml/dlib/dlib/test/blas_bindings/blas_bindings_gemm.cpp
@@ -0,0 +1,311 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "../tester.h"
+#include <dlib/matrix.h>
+
+#ifndef DLIB_USE_BLAS
+#error "BLAS bindings must be used for this test to make any sense"
+#endif
+
+namespace dlib
+{
+ namespace blas_bindings
+ {
+ // This is a little screwy. This function is used inside the BLAS
+ // bindings to count how many times each of the BLAS functions get called.
+#ifdef DLIB_TEST_BLAS_BINDINGS
+ int& counter_gemm() { static int counter = 0; return counter; }
+#endif
+
+ }
+}
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.gemm");
+
+
+ class blas_bindings_gemm_tester : public tester
+ {
+ public:
+ blas_bindings_gemm_tester (
+ ) :
+ tester (
+ "test_gemm", // the command line argument name for this test
+ "Run tests for GEMM routines.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {}
+
+ template <typename matrix_type>
+ void test_gemm_stuff(
+ const matrix_type& c
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ matrix_type b, a;
+ a = c;
+
+ counter_gemm() = 0;
+ b = a*a;
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = a/2*a;
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = a*trans(a) + a;
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = (a+a)*(a+a);
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = a*(a-a);
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = trans(a)*trans(a) + a;
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = trans(trans(trans(a)*a + a));
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = a*a*a*a;
+ DLIB_TEST(counter_gemm() == 3);
+ b = c;
+
+ counter_gemm() = 0;
+ a = a*a*a*a;
+ DLIB_TEST(counter_gemm() == 3);
+ a = c;
+
+ counter_gemm() = 0;
+ a = (b + a*trans(a)*a*3*a)*trans(b);
+ DLIB_TEST(counter_gemm() == 4);
+ a = c;
+
+ counter_gemm() = 0;
+ a = trans((trans(b) + trans(a)*trans(a)*a*3*a)*trans(b));
+ DLIB_TEST(counter_gemm() == 4);
+ a = c;
+
+ counter_gemm() = 0;
+ a = trans((trans(b) + trans(a)*(a)*trans(a)*3*a)*trans(b));
+ DLIB_TEST(counter_gemm() == 4);
+ a = c;
+
+ counter_gemm() = 0;
+ a = trans((trans(b) + trans(a)*(a + b)*trans(a)*3*a)*trans(b));
+ DLIB_TEST_MSG(counter_gemm() == 4, counter_gemm());
+ a = c;
+
+ counter_gemm() = 0;
+ a = trans((trans(b) + trans(a)*(a*8 + b+b+b+b)*trans(a)*3*a)*trans(b));
+ DLIB_TEST_MSG(counter_gemm() == 4, counter_gemm());
+ a = c;
+ }
+
+ template <typename matrix_type>
+ void test_gemm_stuff_conj(
+ const matrix_type& c
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ matrix_type b, a;
+ a = c;
+
+ counter_gemm() = 0;
+ b = a*conj(a);
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = a*trans(conj(a)) + a;
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = conj(trans(a))*trans(a) + a;
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = trans(trans(trans(a)*conj(a) + conj(a)));
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ b = a*a*conj(a)*a;
+ DLIB_TEST(counter_gemm() == 3);
+ b = c;
+
+ counter_gemm() = 0;
+ a = a*trans(conj(a))*a*a;
+ DLIB_TEST(counter_gemm() == 3);
+ a = c;
+
+ counter_gemm() = 0;
+ a = (b + a*trans(conj(a))*a*3*a)*trans(b);
+ DLIB_TEST(counter_gemm() == 4);
+ a = c;
+
+ counter_gemm() = 0;
+ a = (trans((conj(trans(b)) + trans(a)*conj(trans(a))*a*3*a)*trans(b)));
+ DLIB_TEST(counter_gemm() == 4);
+ a = c;
+
+ counter_gemm() = 0;
+ a = ((trans(b) + trans(a)*(a)*trans(a)*3*a)*trans(conj(b)));
+ DLIB_TEST(counter_gemm() == 4);
+ a = c;
+
+ counter_gemm() = 0;
+ a = trans((trans(b) + trans(a)*conj(a + b)*trans(a)*3*a)*trans(b));
+ DLIB_TEST_MSG(counter_gemm() == 4, counter_gemm());
+ a = c;
+
+ counter_gemm() = 0;
+ a = trans((trans(b) + trans(a)*(a*8 + b+b+b+b)*trans(a)*3*conj(a))*trans(b));
+ DLIB_TEST_MSG(counter_gemm() == 4, counter_gemm());
+ a = c;
+ }
+
+ void perform_test (
+ )
+ {
+ using namespace dlib;
+ typedef dlib::memory_manager<char>::kernel_1a mm;
+
+ print_spinner();
+
+ dlog << dlib::LINFO << "test double";
+ {
+ matrix<double> a = randm(4,4);
+ test_gemm_stuff(a);
+ }
+
+ print_spinner();
+ dlog << dlib::LINFO << "test float";
+ {
+ matrix<float> a = matrix_cast<float>(randm(4,4));
+ test_gemm_stuff(a);
+ }
+
+ print_spinner();
+ dlog << dlib::LINFO << "test complex<float>";
+ {
+ matrix<float> a = matrix_cast<float>(randm(4,4));
+ matrix<float> b = matrix_cast<float>(randm(4,4));
+ matrix<complex<float> > c = complex_matrix(a,b);
+ test_gemm_stuff(c);
+ test_gemm_stuff_conj(c);
+ }
+
+ print_spinner();
+ dlog << dlib::LINFO << "test complex<double>";
+ {
+ matrix<double> a = matrix_cast<double>(randm(4,4));
+ matrix<double> b = matrix_cast<double>(randm(4,4));
+ matrix<complex<double> > c = complex_matrix(a,b);
+ test_gemm_stuff(c);
+ test_gemm_stuff_conj(c);
+ }
+
+
+ print_spinner();
+
+ dlog << dlib::LINFO << "test double, column major";
+ {
+ matrix<double,100,100,mm,column_major_layout> a = randm(100,100);
+ test_gemm_stuff(a);
+ }
+
+ print_spinner();
+ dlog << dlib::LINFO << "test float, column major";
+ {
+ matrix<float,100,100,mm,column_major_layout> a = matrix_cast<float>(randm(100,100));
+ test_gemm_stuff(a);
+ }
+
+ print_spinner();
+ dlog << dlib::LINFO << "test complex<double>, column major";
+ {
+ matrix<double,100,100,mm,column_major_layout> a = matrix_cast<double>(randm(100,100));
+ matrix<double,100,100,mm,column_major_layout> b = matrix_cast<double>(randm(100,100));
+ matrix<complex<double>,100,100,mm,column_major_layout > c = complex_matrix(a,b);
+ test_gemm_stuff(c);
+ test_gemm_stuff_conj(c);
+ }
+
+ print_spinner();
+
+ dlog << dlib::LINFO << "test complex<float>, column major";
+ {
+ matrix<float,100,100,mm,column_major_layout> a = matrix_cast<float>(randm(100,100));
+ matrix<float,100,100,mm,column_major_layout> b = matrix_cast<float>(randm(100,100));
+ matrix<complex<float>,100,100,mm,column_major_layout > c = complex_matrix(a,b);
+ test_gemm_stuff(c);
+ test_gemm_stuff_conj(c);
+ }
+
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+ array2d<double> a(100,100);
+ array2d<double> b(100,100);
+ matrix<double> c;
+
+ counter_gemm() = 0;
+ c = mat(a)*mat(b);
+ DLIB_TEST(counter_gemm() == 1);
+
+ counter_gemm() = 0;
+ c = trans(2*mat(a)*mat(b));
+ DLIB_TEST(counter_gemm() == 1);
+ }
+
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+ array2d<double> a(100,100);
+ array2d<double> b(100,100);
+ matrix<double> aa(100,100);
+ matrix<double> bb(100,100);
+ matrix<double> c;
+
+ counter_gemm() = 0;
+ c = mat(&a[0][0],100,100)*mat(&b[0][0],100,100);
+ DLIB_TEST(counter_gemm() == 1);
+ set_ptrm(&c(0,0),100,100) = mat(&a[0][0],100,100)*mat(&b[0][0],100,100);
+ DLIB_TEST(counter_gemm() == 2);
+ set_ptrm(&c(0,0),100,100) = aa*bb;
+ DLIB_TEST(counter_gemm() == 3);
+
+ counter_gemm() = 0;
+ c = trans(2*mat(&a[0][0],100,100)*mat(&b[0][0],100,100));
+ DLIB_TEST(counter_gemm() == 1);
+ set_ptrm(&c(0,0),100,100) = trans(2*mat(&a[0][0],100,100)*mat(&b[0][0],100,100));
+ DLIB_TEST(counter_gemm() == 2);
+ set_ptrm(&c(0,0),100,100) = trans(2*mat(a)*mat(b));
+ DLIB_TEST(counter_gemm() == 3);
+ }
+
+ print_spinner();
+ }
+ };
+
+ blas_bindings_gemm_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/blas_bindings/blas_bindings_gemv.cpp b/ml/dlib/dlib/test/blas_bindings/blas_bindings_gemv.cpp
new file mode 100644
index 000000000..322438313
--- /dev/null
+++ b/ml/dlib/dlib/test/blas_bindings/blas_bindings_gemv.cpp
@@ -0,0 +1,226 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "../tester.h"
+#include <dlib/matrix.h>
+
+#ifndef DLIB_USE_BLAS
+#error "BLAS bindings must be used for this test to make any sense"
+#endif
+
+namespace dlib
+{
+ namespace blas_bindings
+ {
+ // This is a little screwy. This function is used inside the BLAS
+ // bindings to count how many times each of the BLAS functions get called.
+#ifdef DLIB_TEST_BLAS_BINDINGS
+ int& counter_gemv() { static int counter = 0; return counter; }
+#endif
+
+ }
+}
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.gemv");
+
+
+ class blas_bindings_gemv_tester : public tester
+ {
+ public:
+ blas_bindings_gemv_tester (
+ ) :
+ tester (
+ "test_gemv", // the command line argument name for this test
+ "Run tests for GEMV routines.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {}
+
+ template <typename matrix_type, typename rv_type, typename cv_type>
+ void test_gemv_stuff(
+ matrix_type& m,
+ cv_type& cv,
+ rv_type& rv
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ cv_type cv2;
+ rv_type rv2;
+ typedef typename matrix_type::type scalar_type;
+ scalar_type val;
+
+ counter_gemv() = 0;
+ cv2 = m*cv;
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ cv2 = m*2*cv;
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ cv2 = m*2*trans(rv);
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ rv2 = trans(m*2*cv);
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ rv2 = rv*m;
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ rv2 = (rv + rv)*m;
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ rv2 = trans(cv)*m;
+ DLIB_TEST(counter_gemv() == 1);
+ dlog << dlib::LTRACE << 1;
+
+ counter_gemv() = 0;
+ rv2 = trans(cv)*trans(m) + rv*trans(m);
+ DLIB_TEST(counter_gemv() == 2);
+ dlog << dlib::LTRACE << 2;
+
+ counter_gemv() = 0;
+ cv2 = m*trans(trans(cv)*trans(m) + 3*rv*trans(m));
+ DLIB_TEST(counter_gemv() == 3);
+
+ // This does one dot and one gemv
+ counter_gemv() = 0;
+ val = trans(cv)*m*trans(rv);
+ DLIB_TEST_MSG(counter_gemv() == 1, counter_gemv());
+
+ // This does one dot and two gemv
+ counter_gemv() = 0;
+ val = (trans(cv)*m)*(m*trans(rv));
+ DLIB_TEST_MSG(counter_gemv() == 2, counter_gemv());
+
+ // This does one dot and two gemv
+ counter_gemv() = 0;
+ val = trans(cv)*m*trans(m)*trans(rv);
+ DLIB_TEST_MSG(counter_gemv() == 2, counter_gemv());
+ }
+
+
+ template <typename matrix_type, typename rv_type, typename cv_type>
+ void test_gemv_stuff_conj(
+ matrix_type& m,
+ cv_type& cv,
+ rv_type& rv
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ cv_type cv2;
+ rv_type rv2;
+
+ counter_gemv() = 0;
+ cv2 = trans(cv)*conj(m);
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ cv2 = conj(trans(m))*rv;
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ cv2 = conj(trans(m))*trans(cv);
+ DLIB_TEST(counter_gemv() == 1);
+
+ counter_gemv() = 0;
+ cv2 = trans(trans(cv)*conj(2*m) + conj(3*trans(m))*rv + conj(trans(m)*3)*trans(cv));
+ DLIB_TEST(counter_gemv() == 3);
+
+ }
+
+ void perform_test (
+ )
+ {
+ using namespace dlib;
+ typedef dlib::memory_manager<char>::kernel_1a mm;
+
+ dlog << dlib::LINFO << "test double";
+ {
+ matrix<double> m = randm(4,4);
+ matrix<double,0,1> cv = randm(4,1);
+ matrix<double,1,0> rv = randm(1,4);
+ test_gemv_stuff(m,cv,rv);
+ }
+
+ dlog << dlib::LINFO << "test float";
+ {
+ matrix<float> m = matrix_cast<float>(randm(4,4));
+ matrix<float,0,1> cv = matrix_cast<float>(randm(4,1));
+ matrix<float,1,0> rv = matrix_cast<float>(randm(1,4));
+ test_gemv_stuff(m,cv,rv);
+ }
+
+ dlog << dlib::LINFO << "test complex<double>";
+ {
+ matrix<complex<double> > m = complex_matrix(randm(4,4), randm(4,4));
+ matrix<complex<double>,0,1> cv = complex_matrix(randm(4,1), randm(4,1));
+ matrix<complex<double>,1,0> rv = complex_matrix(randm(1,4), randm(1,4));
+ test_gemv_stuff(m,cv,rv);
+ }
+
+ dlog << dlib::LINFO << "test complex<float>";
+ {
+ matrix<complex<float> > m = matrix_cast<complex<float> >(complex_matrix(randm(4,4), randm(4,4)));
+ matrix<complex<float>,0,1> cv = matrix_cast<complex<float> >(complex_matrix(randm(4,1), randm(4,1)));
+ matrix<complex<float>,1,0> rv = matrix_cast<complex<float> >(complex_matrix(randm(1,4), randm(1,4)));
+ test_gemv_stuff(m,cv,rv);
+ }
+
+
+ dlog << dlib::LINFO << "test double";
+ {
+ matrix<double,0,0,mm,column_major_layout> m = randm(4,4);
+ matrix<double,0,1,mm,column_major_layout> cv = randm(4,1);
+ matrix<double,1,0,mm,column_major_layout> rv = randm(1,4);
+ test_gemv_stuff(m,cv,rv);
+ }
+
+ dlog << dlib::LINFO << "test float";
+ {
+ matrix<float,0,0,mm,column_major_layout> m = matrix_cast<float>(randm(4,4));
+ matrix<float,0,1,mm,column_major_layout> cv = matrix_cast<float>(randm(4,1));
+ matrix<float,1,0,mm,column_major_layout> rv = matrix_cast<float>(randm(1,4));
+ test_gemv_stuff(m,cv,rv);
+ }
+
+ dlog << dlib::LINFO << "test complex<double>";
+ {
+ matrix<complex<double>,0,0,mm,column_major_layout > m = complex_matrix(randm(4,4), randm(4,4));
+ matrix<complex<double>,0,1,mm,column_major_layout> cv = complex_matrix(randm(4,1), randm(4,1));
+ matrix<complex<double>,1,0,mm,column_major_layout> rv = complex_matrix(randm(1,4), randm(1,4));
+ test_gemv_stuff(m,cv,rv);
+ }
+
+ dlog << dlib::LINFO << "test complex<float>";
+ {
+ matrix<complex<float>,0,0,mm,column_major_layout > m = matrix_cast<complex<float> >(complex_matrix(randm(4,4), randm(4,4)));
+ matrix<complex<float>,0,1,mm,column_major_layout> cv = matrix_cast<complex<float> >(complex_matrix(randm(4,1), randm(4,1)));
+ matrix<complex<float>,1,0,mm,column_major_layout> rv = matrix_cast<complex<float> >(complex_matrix(randm(1,4), randm(1,4)));
+ test_gemv_stuff(m,cv,rv);
+ }
+
+
+ print_spinner();
+ }
+ };
+
+ blas_bindings_gemv_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/blas_bindings/blas_bindings_ger.cpp b/ml/dlib/dlib/test/blas_bindings/blas_bindings_ger.cpp
new file mode 100644
index 000000000..2aac834d2
--- /dev/null
+++ b/ml/dlib/dlib/test/blas_bindings/blas_bindings_ger.cpp
@@ -0,0 +1,200 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "../tester.h"
+#include <dlib/matrix.h>
+
+#ifndef DLIB_USE_BLAS
+#error "BLAS bindings must be used for this test to make any sense"
+#endif
+
+namespace dlib
+{
+ namespace blas_bindings
+ {
+ // This is a little screwy. This function is used inside the BLAS
+ // bindings to count how many times each of the BLAS functions get called.
+#ifdef DLIB_TEST_BLAS_BINDINGS
+ int& counter_ger() { static int counter = 0; return counter; }
+#endif
+
+ }
+}
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.ger");
+
+
+ class blas_bindings_ger_tester : public tester
+ {
+ public:
+ blas_bindings_ger_tester (
+ ) :
+ tester (
+ "test_ger", // the command line argument name for this test
+ "Run tests for GER routines.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {}
+
+ template <typename matrix_type, typename cv_type, typename rv_type>
+ void test_ger_stuff(
+ matrix_type& m,
+ rv_type& rv,
+ cv_type& cv
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ rv_type rv2;
+ cv_type cv2;
+ matrix_type m2;
+
+ counter_ger() = 0;
+ m2 = m + cv*rv;
+ DLIB_TEST_MSG(counter_ger() == 1, counter_ger());
+
+ counter_ger() = 0;
+ m += trans(rv)*rv;
+ DLIB_TEST(counter_ger() == 1);
+
+ counter_ger() = 0;
+ m += trans(rv)*trans(cv);
+ DLIB_TEST(counter_ger() == 1);
+
+ counter_ger() = 0;
+ m += cv*trans(cv);
+ DLIB_TEST(counter_ger() == 1);
+
+ counter_ger() = 0;
+ m += trans(rv)*rv + trans(cv*3*rv);
+ DLIB_TEST(counter_ger() == 2);
+ }
+
+
+ template <typename matrix_type, typename cv_type, typename rv_type>
+ void test_ger_stuff_conj(
+ matrix_type& m,
+ rv_type& rv,
+ cv_type& cv
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ rv_type rv2;
+ cv_type cv2;
+ matrix_type m2;
+
+ counter_ger() = 0;
+ m += cv*conj(rv);
+ DLIB_TEST_MSG(counter_ger() == 1, counter_ger());
+
+ counter_ger() = 0;
+ m += trans(rv)*conj(rv);
+ DLIB_TEST(counter_ger() == 1);
+
+ counter_ger() = 0;
+ m += trans(rv)*conj(trans(cv));
+ DLIB_TEST(counter_ger() == 1);
+
+ counter_ger() = 0;
+ m += cv*trans(conj(cv));
+ DLIB_TEST(counter_ger() == 1);
+
+ counter_ger() = 0;
+ m += trans(rv)*rv + trans(cv*3*conj(rv));
+ DLIB_TEST(counter_ger() == 2);
+ }
+
+ void perform_test (
+ )
+ {
+ using namespace dlib;
+ typedef dlib::memory_manager<char>::kernel_1a mm;
+
+ dlog << dlib::LINFO << "test double";
+ {
+ matrix<double> m = randm(4,4);
+ matrix<double,1,0> rv = randm(1,4);
+ matrix<double,0,1> cv = randm(4,1);
+ test_ger_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test float";
+ {
+ matrix<float> m = matrix_cast<float>(randm(4,4));
+ matrix<float,1,0> rv = matrix_cast<float>(randm(1,4));
+ matrix<float,0,1> cv = matrix_cast<float>(randm(4,1));
+ test_ger_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<double>";
+ {
+ matrix<complex<double> > m = complex_matrix(randm(4,4), randm(4,4));
+ matrix<complex<double>,1,0> rv = complex_matrix(randm(1,4), randm(1,4));
+ matrix<complex<double>,0,1> cv = complex_matrix(randm(4,1), randm(4,1));
+ test_ger_stuff(m,rv,cv);
+ test_ger_stuff_conj(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<float>";
+ {
+ matrix<complex<float> > m = matrix_cast<complex<float> >(complex_matrix(randm(4,4), randm(4,4)));
+ matrix<complex<float>,1,0> rv = matrix_cast<complex<float> >(complex_matrix(randm(1,4), randm(1,4)));
+ matrix<complex<float>,0,1> cv = matrix_cast<complex<float> >(complex_matrix(randm(4,1), randm(4,1)));
+ test_ger_stuff(m,rv,cv);
+ test_ger_stuff_conj(m,rv,cv);
+ }
+
+
+ dlog << dlib::LINFO << "test double";
+ {
+ matrix<double,0,0,mm,column_major_layout> m = randm(4,4);
+ matrix<double,1,0,mm,column_major_layout> rv = randm(1,4);
+ matrix<double,0,1,mm,column_major_layout> cv = randm(4,1);
+ test_ger_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test float";
+ {
+ matrix<float,0,0,mm,column_major_layout> m = matrix_cast<float>(randm(4,4));
+ matrix<float,1,0,mm,column_major_layout> rv = matrix_cast<float>(randm(1,4));
+ matrix<float,0,1,mm,column_major_layout> cv = matrix_cast<float>(randm(4,1));
+ test_ger_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<double>";
+ {
+ matrix<complex<double>,0,0,mm,column_major_layout > m = complex_matrix(randm(4,4), randm(4,4));
+ matrix<complex<double>,1,0,mm,column_major_layout> rv = complex_matrix(randm(1,4), randm(1,4));
+ matrix<complex<double>,0,1,mm,column_major_layout> cv = complex_matrix(randm(4,1), randm(4,1));
+ test_ger_stuff(m,rv,cv);
+ test_ger_stuff_conj(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<float>";
+ {
+ matrix<complex<float>,0,0,mm,column_major_layout > m = matrix_cast<complex<float> >(complex_matrix(randm(4,4), randm(4,4)));
+ matrix<complex<float>,1,0,mm,column_major_layout> rv = matrix_cast<complex<float> >(complex_matrix(randm(1,4), randm(1,4)));
+ matrix<complex<float>,0,1,mm,column_major_layout> cv = matrix_cast<complex<float> >(complex_matrix(randm(4,1), randm(4,1)));
+ test_ger_stuff(m,rv,cv);
+ test_ger_stuff_conj(m,rv,cv);
+ }
+
+
+ print_spinner();
+ }
+ };
+
+ blas_bindings_ger_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/blas_bindings/blas_bindings_scal_axpy.cpp b/ml/dlib/dlib/test/blas_bindings/blas_bindings_scal_axpy.cpp
new file mode 100644
index 000000000..d1a7b99e4
--- /dev/null
+++ b/ml/dlib/dlib/test/blas_bindings/blas_bindings_scal_axpy.cpp
@@ -0,0 +1,261 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "../tester.h"
+#include <dlib/matrix.h>
+
+#ifndef DLIB_USE_BLAS
+#error "BLAS bindings must be used for this test to make any sense"
+#endif
+
+namespace dlib
+{
+ namespace blas_bindings
+ {
+ // This is a little screwy. This function is used inside the BLAS
+ // bindings to count how many times each of the BLAS functions get called.
+#ifdef DLIB_TEST_BLAS_BINDINGS
+ int& counter_axpy() { static int counter = 0; return counter; }
+ int& counter_scal() { static int counter = 0; return counter; }
+#endif
+
+ }
+}
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.scal_axpy");
+
+
+ class blas_bindings_scal_axpy_tester : public tester
+ {
+ public:
+ blas_bindings_scal_axpy_tester (
+ ) :
+ tester (
+ "test_scal_axpy", // the command line argument name for this test
+ "Run tests for DOT routines.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {}
+
+ template <typename matrix_type, typename cv_type, typename rv_type>
+ void test_scal_axpy_stuff(
+ matrix_type& m,
+ rv_type& rv,
+ cv_type& cv
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ rv_type rv2 = rv;
+ cv_type cv2 = cv;
+ matrix_type m2 = m;
+ typedef typename matrix_type::type scalar_type;
+ scalar_type val;
+
+ counter_scal() = 0;
+ m = 5*m;
+ DLIB_TEST(counter_scal() == 1);
+
+ counter_scal() = 0;
+ rv = 5*rv;
+ DLIB_TEST(counter_scal() == 1);
+
+ counter_scal() = 0;
+ rv = 5*rv;
+ DLIB_TEST(counter_scal() == 1);
+
+
+ counter_axpy() = 0;
+ m2 += 5*m;
+ DLIB_TEST(counter_axpy() == 1);
+
+ counter_axpy() = 0;
+ rv2 += 5*rv;
+ DLIB_TEST(counter_axpy() == 1);
+
+ counter_axpy() = 0;
+ rv2 += 5*rv;
+ DLIB_TEST(counter_axpy() == 1);
+
+
+
+ counter_scal() = 0;
+ m = m*5;
+ DLIB_TEST(counter_scal() == 1);
+
+ counter_scal() = 0;
+ rv = rv*5;
+ DLIB_TEST(counter_scal() == 1);
+
+ counter_scal() = 0;
+ cv = cv*5;
+ DLIB_TEST(counter_scal() == 1);
+
+
+ counter_axpy() = 0;
+ m2 += m*5;
+ DLIB_TEST(counter_axpy() == 1);
+
+ counter_axpy() = 0;
+ rv2 += rv*5;
+ DLIB_TEST(counter_axpy() == 1);
+
+ counter_axpy() = 0;
+ cv2 += cv*5;
+ DLIB_TEST(counter_axpy() == 1);
+
+
+
+
+ counter_axpy() = 0;
+ m2 = m2 + m*5;
+ DLIB_TEST(counter_axpy() == 1);
+
+ counter_axpy() = 0;
+ rv2 = rv2 + rv*5;
+ DLIB_TEST(counter_axpy() == 1);
+
+ counter_axpy() = 0;
+ cv2 = cv2 + cv*5;
+ DLIB_TEST(counter_axpy() == 1);
+
+
+ counter_axpy() = 0;
+ cv2 = 1;
+ cv = 1;
+ cv2 = 2*cv2 + cv*5;
+ DLIB_TEST(counter_axpy() == 1);
+ DLIB_TEST(max(abs(cv2 - 7)) == 0);
+
+
+ counter_axpy() = 0;
+ rv2 = 1;
+ rv = 1;
+ rv2 = 2*rv2 + rv*5;
+ DLIB_TEST(counter_axpy() == 1);
+ DLIB_TEST(max(abs(rv2 - 7)) == 0);
+
+ counter_axpy() = 0;
+ m2 = 1;
+ m = 1;
+ m2 = 2*m2 + m*5;
+ DLIB_TEST(counter_axpy() == 1);
+ DLIB_TEST(max(abs(m2 - 7)) == 0);
+
+
+ if (is_same_type<typename matrix_type::layout_type, row_major_layout>::value)
+ {
+ counter_axpy() = 0;
+ m2 = 1;
+ m = 1;
+ set_ptrm(&m2(0,0),m2.nr(),m2.nc()) = 2*m2 + m*5;
+ DLIB_TEST(max(abs(m2 - 7)) == 0);
+ DLIB_TEST(counter_axpy() == 1);
+
+ counter_axpy() = 0;
+ m2 = 1;
+ m = 1;
+ set_ptrm(&m2(0,0),m2.nr(),m2.nc()) = 2*mat(&m2(0,0),m2.nr(),m2.nc()) + mat(&m(0,0),m.nr(),m.nc())*5;
+ DLIB_TEST(max(abs(m2 - 7)) == 0);
+ DLIB_TEST(counter_axpy() == 1);
+
+ counter_axpy() = 0;
+ m2 = 1;
+ m = 1;
+ m2 = 2*mat(&m2(0,0),m2.nr(),m2.nc()) + mat(&m(0,0),m.nr(),m.nc())*5;
+ DLIB_TEST(max(abs(m2 - 7)) == 0);
+ DLIB_TEST(counter_axpy() == 1);
+ }
+
+ }
+
+
+
+ void perform_test (
+ )
+ {
+ using namespace dlib;
+ typedef dlib::memory_manager<char>::kernel_1a mm;
+
+ dlog << dlib::LINFO << "test double";
+ {
+ matrix<double> m = randm(4,4);
+ matrix<double,1,0> rv = randm(1,4);
+ matrix<double,0,1> cv = randm(4,1);
+ test_scal_axpy_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test float";
+ {
+ matrix<float> m = matrix_cast<float>(randm(4,4));
+ matrix<float,1,0> rv = matrix_cast<float>(randm(1,4));
+ matrix<float,0,1> cv = matrix_cast<float>(randm(4,1));
+ test_scal_axpy_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<double>";
+ {
+ matrix<complex<double> > m = complex_matrix(randm(4,4), randm(4,4));
+ matrix<complex<double>,1,0> rv = complex_matrix(randm(1,4), randm(1,4));
+ matrix<complex<double>,0,1> cv = complex_matrix(randm(4,1), randm(4,1));
+ test_scal_axpy_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<float>";
+ {
+ matrix<complex<float> > m = matrix_cast<complex<float> >(complex_matrix(randm(4,4), randm(4,4)));
+ matrix<complex<float>,1,0> rv = matrix_cast<complex<float> >(complex_matrix(randm(1,4), randm(1,4)));
+ matrix<complex<float>,0,1> cv = matrix_cast<complex<float> >(complex_matrix(randm(4,1), randm(4,1)));
+ test_scal_axpy_stuff(m,rv,cv);
+ }
+
+
+ dlog << dlib::LINFO << "test double, column major";
+ {
+ matrix<double,0,0,mm,column_major_layout> m = randm(4,4);
+ matrix<double,1,0,mm,column_major_layout> rv = randm(1,4);
+ matrix<double,0,1,mm,column_major_layout> cv = randm(4,1);
+ test_scal_axpy_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test float, column major";
+ {
+ matrix<float,0,0,mm,column_major_layout> m = matrix_cast<float>(randm(4,4));
+ matrix<float,1,0,mm,column_major_layout> rv = matrix_cast<float>(randm(1,4));
+ matrix<float,0,1,mm,column_major_layout> cv = matrix_cast<float>(randm(4,1));
+ test_scal_axpy_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<double>, column major";
+ {
+ matrix<complex<double>,0,0,mm,column_major_layout > m = complex_matrix(randm(4,4), randm(4,4));
+ matrix<complex<double>,1,0,mm,column_major_layout> rv = complex_matrix(randm(1,4), randm(1,4));
+ matrix<complex<double>,0,1,mm,column_major_layout> cv = complex_matrix(randm(4,1), randm(4,1));
+ test_scal_axpy_stuff(m,rv,cv);
+ }
+
+ dlog << dlib::LINFO << "test complex<float>, column major";
+ {
+ matrix<complex<float>,0,0,mm,column_major_layout > m = matrix_cast<complex<float> >(complex_matrix(randm(4,4), randm(4,4)));
+ matrix<complex<float>,1,0,mm,column_major_layout> rv = matrix_cast<complex<float> >(complex_matrix(randm(1,4), randm(1,4)));
+ matrix<complex<float>,0,1,mm,column_major_layout> cv = matrix_cast<complex<float> >(complex_matrix(randm(4,1), randm(4,1)));
+ test_scal_axpy_stuff(m,rv,cv);
+ }
+
+
+ print_spinner();
+ }
+ };
+
+ blas_bindings_scal_axpy_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/blas_bindings/vector.cpp b/ml/dlib/dlib/test/blas_bindings/vector.cpp
new file mode 100644
index 000000000..0a6f5f301
--- /dev/null
+++ b/ml/dlib/dlib/test/blas_bindings/vector.cpp
@@ -0,0 +1,115 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "../tester.h"
+#include <dlib/geometry.h>
+#include <dlib/matrix.h>
+
+#ifndef DLIB_USE_BLAS
+#error "BLAS bindings must be used for this test to make any sense"
+#endif
+
+namespace dlib
+{
+ namespace blas_bindings
+ {
+
+#ifdef DLIB_TEST_BLAS_BINDINGS
+ extern int& counter_gemm();
+ extern int& counter_gemv();
+ extern int& counter_ger();
+ extern int& counter_dot();
+#endif
+
+ }
+}
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.vector");
+
+
+ class vector_tester : public tester
+ {
+ public:
+ vector_tester (
+ ) :
+ tester (
+ "test_vector", // the command line argument name for this test
+ "Run tests on dlib::vector.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {}
+
+ template <typename type>
+ void test_vector(
+ ) const
+ {
+ using namespace dlib;
+ using namespace dlib::blas_bindings;
+
+ dlib::vector<type,2> a2, b2, c2;
+ dlib::vector<type,3> a3, b3, c3;
+
+ matrix<type> mat2(2,2), mat3(3,3);
+ mat2 = 0;
+ mat3 = 0;
+
+ type var = 0;
+
+ // We want to make sure that the BLAS bindings are being called for the 2D and 3D vectors. That would
+ // be very slow.
+ counter_gemm() = 0;
+ counter_gemv() = 0;
+ counter_ger() = 0;
+ counter_dot() = 0;
+
+ var = trans(a2)*(a2);
+ var = dot(a2,a2);
+
+ a2 = mat2*b2;
+ var = trans(b2)*mat2*b2;
+
+ var = trans(a3)*(a3);
+ var = dot(a3,a3);
+
+ a3 = mat3*b3;
+ var = trans(b3)*mat3*b3;
+
+ mat3 = c3*trans(a3);
+ mat2 = c2*trans(a2);
+
+ DLIB_TEST(counter_gemm() == 0 && counter_gemv() == 0 && counter_ger() == 0 && counter_dot() == 0);
+
+ }
+
+ void perform_test (
+ )
+ {
+ using namespace dlib;
+
+ dlog << dlib::LINFO << "test double";
+ test_vector<double>();
+
+ dlog << dlib::LINFO << "test float";
+ test_vector<float>();
+
+ dlog << dlib::LINFO << "test int";
+ test_vector<int>();
+
+ dlog << dlib::LINFO << "test short";
+ test_vector<short>();
+
+ print_spinner();
+ }
+ };
+
+ vector_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/bridge.cpp b/ml/dlib/dlib/test/bridge.cpp
new file mode 100644
index 000000000..36d270c74
--- /dev/null
+++ b/ml/dlib/dlib/test/bridge.cpp
@@ -0,0 +1,259 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/bridge.h>
+#include <dlib/type_safe_union.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.bridge");
+
+ const unsigned short testing_port = 41238;
+
+ void do_test1()
+ {
+ dlib::pipe<int> in(0), out(0);
+
+ bridge b1(connect_to_ip_and_port("127.0.0.1",testing_port), receive(in));
+ bridge b2(listen_on_port(testing_port), transmit(out));
+
+ for (int i = 0; i < 100; ++i)
+ {
+ int val = i;
+ out.enqueue(val);
+ val = 0;
+ in.dequeue(val);
+ DLIB_TEST(val == i);
+ }
+ }
+
+ void do_test2()
+ {
+ dlib::pipe<int> in(0), out(0), echo_pipe(0);
+
+ bridge b2(listen_on_port(testing_port), transmit(out), receive(in));
+ bridge echo(connect_to_ip_and_port("127.0.0.1",testing_port), receive(echo_pipe), transmit(echo_pipe));
+
+ for (int i = 0; i < 100; ++i)
+ {
+ int val = i;
+ out.enqueue(val);
+ val = 0;
+ in.dequeue(val);
+ DLIB_TEST(val == i);
+ }
+ }
+
+ void do_test3()
+ {
+ dlib::pipe<int> in(10), out(10), echo_pipe(10);
+
+ bridge b2(listen_on_port(testing_port), transmit(out), receive(in));
+ bridge echo(connect_to_ip_and_port("127.0.0.1",testing_port), receive(echo_pipe), transmit(echo_pipe));
+
+ b2.reconfigure(listen_on_port(testing_port), transmit(out), receive(in));
+
+ for (int i = 0; i < 100; ++i)
+ {
+ int val = i;
+ out.enqueue(val);
+ val = 0;
+ in.dequeue(val);
+ DLIB_TEST(val == i);
+ }
+ }
+
+ void do_test4()
+ {
+ dlib::pipe<int> in(0), out(0), echo_pipe(0);
+
+ bridge b2, echo;
+ b2.reconfigure(listen_on_port(testing_port), receive(in), transmit(out));
+ echo.reconfigure(connect_to_ip_and_port("127.0.0.1",testing_port), transmit(echo_pipe), receive(echo_pipe));
+
+ for (int i = 0; i < 100; ++i)
+ {
+ int val = i;
+ out.enqueue(val);
+ val = 0;
+ in.dequeue(val);
+ DLIB_TEST(val == i);
+ }
+ }
+
+ void do_test5(int pipe_size)
+ {
+ typedef type_safe_union<int, bridge_status> tsu_type;
+
+ dlib::pipe<tsu_type> out(pipe_size);
+ dlib::pipe<tsu_type> in(pipe_size);
+ dlib::pipe<bridge_status> out_status(pipe_size);
+
+ bridge b1(connect_to_ip_and_port("127.0.0.1",testing_port), receive(in));
+ tsu_type msg;
+
+ msg = b1.get_bridge_status();
+ DLIB_TEST(msg.contains<bridge_status>() == true);
+ DLIB_TEST(msg.get<bridge_status>().is_connected == false);
+ DLIB_TEST(msg.get<bridge_status>().foreign_ip == "");
+ DLIB_TEST(msg.get<bridge_status>().foreign_port == 0);
+
+ {
+ bridge b2(listen_on_port(testing_port), transmit(out), receive(out_status));
+
+ in.dequeue(msg);
+ DLIB_TEST(msg.contains<bridge_status>() == true);
+ DLIB_TEST(msg.get<bridge_status>().is_connected == true);
+ DLIB_TEST(msg.get<bridge_status>().foreign_ip == "127.0.0.1");
+ DLIB_TEST(msg.get<bridge_status>().foreign_port == testing_port);
+ msg = b1.get_bridge_status();
+ DLIB_TEST(msg.contains<bridge_status>() == true);
+ DLIB_TEST(msg.get<bridge_status>().is_connected == true);
+ DLIB_TEST(msg.get<bridge_status>().foreign_ip == "127.0.0.1");
+ DLIB_TEST(msg.get<bridge_status>().foreign_port == testing_port);
+
+ bridge_status temp;
+ out_status.dequeue(temp);
+ DLIB_TEST(temp.is_connected == true);
+ DLIB_TEST(temp.foreign_ip == "127.0.0.1");
+
+ for (int i = 0; i < 100; ++i)
+ {
+ msg = i;
+ out.enqueue(msg);
+
+ msg.get<int>() = 0;
+
+ in.dequeue(msg);
+ DLIB_TEST(msg.contains<int>() == true);
+ DLIB_TEST(msg.get<int>() == i);
+ }
+
+ }
+
+ in.dequeue(msg);
+ DLIB_TEST(msg.contains<bridge_status>() == true);
+ DLIB_TEST(msg.get<bridge_status>().is_connected == false);
+ DLIB_TEST(msg.get<bridge_status>().foreign_ip == "127.0.0.1");
+ DLIB_TEST(msg.get<bridge_status>().foreign_port == testing_port);
+ }
+
+ void do_test5_5(int pipe_size)
+ {
+ typedef type_safe_union<int, bridge_status> tsu_type;
+
+ dlib::pipe<tsu_type> out(pipe_size);
+ dlib::pipe<tsu_type> in(pipe_size);
+ dlib::pipe<bridge_status> out_status(pipe_size);
+
+ bridge b1(connect_to_ip_and_port("127.0.0.1",testing_port), receive(in));
+ tsu_type msg;
+
+ bridge b2(listen_on_port(testing_port), transmit(out), receive(out_status));
+
+ in.dequeue(msg);
+ DLIB_TEST(msg.contains<bridge_status>() == true);
+ DLIB_TEST(msg.get<bridge_status>().is_connected == true);
+ DLIB_TEST(msg.get<bridge_status>().foreign_ip == "127.0.0.1");
+ DLIB_TEST(msg.get<bridge_status>().foreign_port == testing_port);
+
+ bridge_status temp;
+ out_status.dequeue(temp);
+ DLIB_TEST(temp.is_connected == true);
+ DLIB_TEST(temp.foreign_ip == "127.0.0.1");
+
+ for (int i = 0; i < 100; ++i)
+ {
+ msg = i;
+ out.enqueue(msg);
+
+ msg.get<int>() = 0;
+
+ in.dequeue(msg);
+ DLIB_TEST(msg.contains<int>() == true);
+ DLIB_TEST(msg.get<int>() == i);
+ }
+
+ b2.clear();
+ msg = b2.get_bridge_status();
+ DLIB_TEST(msg.contains<bridge_status>() == true);
+ DLIB_TEST(msg.get<bridge_status>().is_connected == false);
+ DLIB_TEST(msg.get<bridge_status>().foreign_ip == "");
+ DLIB_TEST(msg.get<bridge_status>().foreign_port == 0);
+
+ in.dequeue(msg);
+ DLIB_TEST(msg.contains<bridge_status>() == true);
+ DLIB_TEST(msg.get<bridge_status>().is_connected == false);
+ DLIB_TEST(msg.get<bridge_status>().foreign_ip == "127.0.0.1");
+ DLIB_TEST(msg.get<bridge_status>().foreign_port == testing_port);
+ }
+
+ void do_test6()
+ {
+ dlib::pipe<int> in(0), out(300);
+
+ bridge b1(connect_to_ip_and_port("127.0.0.1",testing_port), receive(in));
+ bridge b2(listen_on_port(testing_port), transmit(out));
+
+ for (int i = 0; i < 100; ++i)
+ {
+ int val = i;
+ out.enqueue(val);
+ }
+
+ int val = 10;
+ in.dequeue(val);
+ DLIB_TEST(val == 0);
+ dlib::sleep(100);
+ in.dequeue(val);
+ DLIB_TEST(val == 1);
+ dlib::sleep(100);
+ }
+
+ class test_bridge : public tester
+ {
+ public:
+ test_bridge (
+ ) :
+ tester ("test_bridge",
+ "Runs tests on the bridge component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing bridge, using local port number of " << testing_port;
+
+ print_spinner();
+ do_test1();
+ print_spinner();
+ do_test2();
+ print_spinner();
+ do_test3();
+ print_spinner();
+ do_test4();
+ print_spinner();
+ for (int i = 0; i < 5; ++i)
+ do_test5(i);
+ do_test5_5(1);
+ print_spinner();
+ do_test6();
+ }
+ } a;
+
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/bsp.cpp b/ml/dlib/dlib/test/bsp.cpp
new file mode 100644
index 000000000..04367c1d3
--- /dev/null
+++ b/ml/dlib/dlib/test/bsp.cpp
@@ -0,0 +1,566 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/bsp.h>
+#include <dlib/threads.h>
+#include <dlib/pipe.h>
+#include <dlib/matrix.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.bsp");
+
+
+ template <typename funct>
+ struct callfunct_helper
+ {
+ callfunct_helper (
+ funct f_,
+ int port_,
+ bool& error_occurred_
+ ) :f(f_), port(port_), error_occurred(error_occurred_) {}
+
+ funct f;
+ int port;
+ bool& error_occurred;
+
+ void operator() (
+ ) const
+ {
+ try
+ {
+ bsp_listen(port, f);
+ }
+ catch (exception& e)
+ {
+ dlog << LERROR << "error calling bsp_listen(): " << e.what();
+ error_occurred = true;
+ }
+ }
+ };
+
+ template <typename funct>
+ callfunct_helper<funct> callfunct(funct f, int port, bool& error_occurred)
+ {
+ return callfunct_helper<funct>(f,port,error_occurred);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename funct>
+ struct callfunct_helper_pn
+ {
+ callfunct_helper_pn (
+ funct f_,
+ int port_,
+ bool& error_occurred_,
+ dlib::pipe<unsigned short>& port_pipe_
+ ) :f(f_), port(port_), error_occurred(error_occurred_), port_pipe(port_pipe_) {}
+
+ funct f;
+ int port;
+ bool& error_occurred;
+ dlib::pipe<unsigned short>& port_pipe;
+
+ struct helper
+ {
+ helper (
+ dlib::pipe<unsigned short>& port_pipe_
+ ) : port_pipe(port_pipe_) {}
+
+ dlib::pipe<unsigned short>& port_pipe;
+
+ void operator() (unsigned short p) { port_pipe.enqueue(p); }
+ };
+
+ void operator() (
+ ) const
+ {
+ try
+ {
+ bsp_listen_dynamic_port(port, helper(port_pipe), f);
+ }
+ catch (exception& e)
+ {
+ dlog << LERROR << "error calling bsp_listen_dynamic_port(): " << e.what();
+ error_occurred = true;
+ }
+ }
+ };
+
+ template <typename funct>
+ callfunct_helper_pn<funct> callfunct(funct f, int port, bool& error_occurred, dlib::pipe<unsigned short>& port_pipe)
+ {
+ return callfunct_helper_pn<funct>(f,port,error_occurred,port_pipe);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void sum_array_driver (
+ bsp_context& obj,
+ const std::vector<int>& v,
+ int& result
+ )
+ {
+ obj.broadcast(v);
+
+ result = 0;
+ int val;
+ while(obj.try_receive(val))
+ result += val;
+ }
+
+ void sum_array_other (
+ bsp_context& obj
+ )
+ {
+ std::vector<int> v;
+ obj.receive(v);
+
+ int sum = 0;
+ for (unsigned long i = 0; i < v.size(); ++i)
+ sum += v[i];
+
+ obj.send(sum, 0);
+
+
+ }
+
+
+ void dotest1()
+ {
+ dlog << LINFO << "start dotest1()";
+ print_spinner();
+ bool error_occurred = false;
+ {
+ thread_function t1(callfunct(sum_array_other, 12345, error_occurred));
+ thread_function t2(callfunct(sum_array_other, 12346, error_occurred));
+ thread_function t3(callfunct(sum_array_other, 12347, error_occurred));
+ std::vector<int> v;
+ int true_value = 0;
+ for (int i = 0; i < 10; ++i)
+ {
+ v.push_back(i);
+ true_value += i;
+ }
+
+ // wait a little bit for the threads to start up
+ dlib::sleep(200);
+
+ try
+ {
+ int result;
+ std::vector<network_address> hosts;
+ hosts.push_back("127.0.0.1:12345");
+ hosts.push_back("localhost:12346");
+ hosts.push_back("127.0.0.1:12347");
+ bsp_connect(hosts, sum_array_driver, dlib::ref(v), dlib::ref(result));
+
+ dlog << LINFO << "result: "<< result;
+ dlog << LINFO << "should be: "<< 3*true_value;
+ DLIB_TEST(result == 3*true_value);
+ }
+ catch (std::exception& e)
+ {
+ dlog << LERROR << "error during bsp_context: " << e.what();
+ DLIB_TEST(false);
+ }
+ }
+ DLIB_TEST(error_occurred == false);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <unsigned long id>
+ void test2_job(bsp_context& obj)
+ {
+ if (obj.node_id() == id)
+ dlib::sleep(100);
+ }
+
+ template <unsigned long id>
+ void dotest2()
+ {
+ dlog << LINFO << "start dotest2()";
+ print_spinner();
+ bool error_occurred = false;
+ {
+ thread_function t1(callfunct(test2_job<id>, 12345, error_occurred));
+ thread_function t2(callfunct(test2_job<id>, 12346, error_occurred));
+ thread_function t3(callfunct(test2_job<id>, 12347, error_occurred));
+
+ // wait a little bit for the threads to start up
+ dlib::sleep(200);
+
+ try
+ {
+ std::vector<network_address> hosts;
+ hosts.push_back("127.0.0.1:12345");
+ hosts.push_back("127.0.0.1:12346");
+ hosts.push_back("127.0.0.1:12347");
+ bsp_connect(hosts, test2_job<id>);
+ }
+ catch (std::exception& e)
+ {
+ dlog << LERROR << "error during bsp_context: " << e.what();
+ DLIB_TEST(false);
+ }
+
+ }
+ DLIB_TEST(error_occurred == false);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test3_job_driver(bsp_context& obj, int& result)
+ {
+
+ obj.broadcast(obj.node_id());
+
+ int accum = 0;
+ int temp = 0;
+ while(obj.try_receive(temp))
+ accum += temp;
+
+ // send to node 1 so it can sum everything
+ if (obj.node_id() != 1)
+ obj.send(accum, 1);
+
+ while(obj.try_receive(temp))
+ accum += temp;
+
+ // Now hop the accum values along the nodes until the value from node 1 gets to
+ // node 0.
+ obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes());
+ obj.receive(accum);
+ obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes());
+ obj.receive(accum);
+ obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes());
+ obj.receive(accum);
+
+ // this whole block is a noop since it doesn't end up doing anything.
+ for (int k = 0; k < 100; ++k)
+ {
+ dlog << LINFO << "k: " << k;
+ for (int i = 0; i < 4; ++i)
+ {
+ obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes());
+ obj.receive(accum);
+ }
+ }
+
+
+ dlog << LINFO << "TERMINATE";
+ if (obj.node_id() == 0)
+ result = accum;
+ }
+
+
+ void test3_job(bsp_context& obj)
+ {
+ int junk;
+ test3_job_driver(obj, junk);
+ }
+
+
+ void dotest3()
+ {
+ dlog << LINFO << "start dotest3()";
+ print_spinner();
+ bool error_occurred = false;
+ {
+ dlib::pipe<unsigned short> ports(5);
+ thread_function t1(callfunct(test3_job, 12345, error_occurred, ports));
+ thread_function t2(callfunct(test3_job, 0, error_occurred, ports));
+ thread_function t3(callfunct(test3_job, 12347, error_occurred, ports));
+
+
+ try
+ {
+ std::vector<network_address> hosts;
+ unsigned short port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ int result = 0;
+ const int expected = 1+2+3 + 0+2+3 + 0+1+3 + 0+1+2;
+ bsp_connect(hosts, test3_job_driver, dlib::ref(result));
+
+ dlog << LINFO << "result: " << result;
+ dlog << LINFO << "should be: " << expected;
+ DLIB_TEST(result == expected);
+ }
+ catch (std::exception& e)
+ {
+ dlog << LERROR << "error during bsp_context: " << e.what();
+ DLIB_TEST(false);
+ }
+
+ }
+ DLIB_TEST(error_occurred == false);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test4_job_driver(bsp_context& obj, int& result)
+ {
+
+ obj.broadcast(obj.node_id());
+
+ int accum = 0;
+ int temp = 0;
+ while(obj.try_receive(temp))
+ accum += temp;
+
+ // send to node 1 so it can sum everything
+ if (obj.node_id() != 1)
+ obj.send(accum, 1);
+
+ while(obj.try_receive(temp))
+ accum += temp;
+
+ // Now hop the accum values along the nodes until the value from node 1 gets to
+ // node 0.
+ obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes());
+ obj.receive(accum);
+ obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes());
+ obj.receive(accum);
+ obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes());
+ obj.receive(accum);
+
+ // this whole block is a noop since it doesn't end up doing anything.
+ for (int k = 0; k < 40; ++k)
+ {
+ dlog << LINFO << "k: " << k;
+ for (int i = 0; i < 4; ++i)
+ {
+ obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes());
+ obj.receive(accum);
+
+ obj.receive();
+ }
+ }
+
+
+ dlog << LINFO << "TERMINATE";
+ if (obj.node_id() == 0)
+ result = accum;
+ }
+
+
+ void test4_job(bsp_context& obj)
+ {
+ int junk;
+ test4_job_driver(obj, junk);
+ }
+
+
+ void dotest4()
+ {
+ dlog << LINFO << "start dotest4()";
+ print_spinner();
+ bool error_occurred = false;
+ {
+ dlib::pipe<unsigned short> ports(5);
+ thread_function t1(callfunct(test4_job, 0, error_occurred, ports));
+ thread_function t2(callfunct(test4_job, 0, error_occurred, ports));
+ thread_function t3(callfunct(test4_job, 0, error_occurred, ports));
+
+
+ try
+ {
+ std::vector<network_address> hosts;
+ unsigned short port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ int result = 0;
+ const int expected = 1+2+3 + 0+2+3 + 0+1+3 + 0+1+2;
+ bsp_connect(hosts, test4_job_driver, dlib::ref(result));
+
+ dlog << LINFO << "result: " << result;
+ dlog << LINFO << "should be: " << expected;
+ DLIB_TEST(result == expected);
+ }
+ catch (std::exception& e)
+ {
+ dlog << LERROR << "error during bsp_context: " << e.what();
+ DLIB_TEST(false);
+ }
+
+ }
+ DLIB_TEST(error_occurred == false);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test5_job(
+ bsp_context& ,
+ int& val
+ )
+ {
+ val = 25;
+ }
+
+ void dotest5()
+ {
+ dlog << LINFO << "start dotest5()";
+ print_spinner();
+ std::vector<network_address> hosts;
+ int val = 0;
+ bsp_connect(hosts, test5_job, dlib::ref(val));
+ DLIB_TEST(val == 25);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ double f ( double x)
+ {
+ return std::pow(x-2.0, 2.0);
+ }
+
+
+ void bsp_job_node_0 (
+ bsp_context& context,
+ double& min_value,
+ double& optimal_x
+ )
+ {
+ double left = -100;
+ double right = 100;
+
+ min_value = std::numeric_limits<double>::infinity();
+ double interval_width = std::abs(right-left);
+
+ // This is doing a BSP based grid search for the minimum of f(). Here we
+ // do 100 iterations where we keep shrinking the grid size.
+ for (int i = 0; i < 100; ++i)
+ {
+ context.broadcast(left);
+ context.broadcast(right);
+
+ for (unsigned int k = 1; k < context.number_of_nodes(); ++k)
+ {
+ std::pair<double,double> val;
+ context.receive(val);
+ if (val.second < min_value)
+ {
+ min_value = val.second;
+ optimal_x = val.first;
+ }
+ }
+
+ interval_width *= 0.5;
+ left = optimal_x - interval_width/2;
+ right = optimal_x + interval_width/2;
+ }
+ }
+
+
+ void bsp_job_other_nodes (
+ bsp_context& context
+ )
+ {
+ double left, right;
+ while (context.try_receive(left))
+ {
+ context.receive(right);
+
+ const double l = (context.node_id()-1)/(context.number_of_nodes()-1.0);
+ const double r = context.node_id() /(context.number_of_nodes()-1.0);
+
+ const double width = right-left;
+ matrix<double> values_to_check = linspace(left +l*width, left + r*width, 100);
+
+ double best_x = 0;
+ double best_val = std::numeric_limits<double>::infinity();
+ for (long j = 0; j < values_to_check.size(); ++j)
+ {
+ double temp = f(values_to_check(j));
+ if (temp < best_val)
+ {
+ best_val = temp;
+ best_x = values_to_check(j);
+ }
+ }
+
+ context.send(make_pair(best_x, best_val), 0);
+ }
+ }
+
+ void dotest6()
+ {
+ dlog << LINFO << "start dotest6()";
+ print_spinner();
+ bool error_occurred = false;
+ {
+ dlib::pipe<unsigned short> ports(5);
+ thread_function t1(callfunct(bsp_job_other_nodes, 0, error_occurred, ports));
+ thread_function t2(callfunct(bsp_job_other_nodes, 0, error_occurred, ports));
+ thread_function t3(callfunct(bsp_job_other_nodes, 0, error_occurred, ports));
+
+
+ try
+ {
+ std::vector<network_address> hosts;
+ unsigned short port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port;
+ double min_value = 10, optimal_x = 0;
+ bsp_connect(hosts, bsp_job_node_0, dlib::ref(min_value), dlib::ref(optimal_x));
+
+ dlog << LINFO << "min_value: " << min_value;
+ dlog << LINFO << "optimal_x: " << optimal_x;
+ DLIB_TEST(std::abs(min_value - 0) < 1e-14);
+ DLIB_TEST(std::abs(optimal_x - 2) < 1e-14);
+ }
+ catch (std::exception& e)
+ {
+ dlog << LERROR << "error during bsp_context: " << e.what();
+ DLIB_TEST(false);
+ }
+
+ }
+ DLIB_TEST(error_occurred == false);
+ }
+// ----------------------------------------------------------------------------------------
+
+ class bsp_tester : public tester
+ {
+
+ public:
+ bsp_tester (
+ ) :
+ tester ("test_bsp",
+ "Runs tests on the BSP components.")
+ {}
+
+ void perform_test (
+ )
+ {
+ for (int i = 0; i < 3; ++i)
+ {
+ dotest1();
+ dotest2<0>();
+ dotest2<1>();
+ dotest2<2>();
+ dotest3();
+ dotest4();
+ dotest5();
+ dotest6();
+ }
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/byte_orderer.cpp b/ml/dlib/dlib/test/byte_orderer.cpp
new file mode 100644
index 000000000..7200c1b4a
--- /dev/null
+++ b/ml/dlib/dlib/test/byte_orderer.cpp
@@ -0,0 +1,111 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <cmath>
+#include <dlib/byte_orderer.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.byte_orderer");
+
+
+ class byte_orderer_tester : public tester
+ {
+ public:
+ byte_orderer_tester (
+ ) :
+ tester ("test_byte_orderer",
+ "Runs tests on the byte_orderer component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ byte_orderer bo;
+
+ union data
+ {
+ unsigned char b[4];
+ dlib::uint32 val;
+ };
+
+ data a;
+
+ a.val = 1;
+
+ if (bo.host_is_little_endian())
+ {
+ DLIB_TEST(a.b[0] == 1);
+ DLIB_TEST(a.b[1] == 0);
+ DLIB_TEST(a.b[2] == 0);
+ DLIB_TEST(a.b[3] == 0);
+
+ bo.host_to_big(a.val);
+
+ DLIB_TEST(a.b[0] == 0);
+ DLIB_TEST(a.b[1] == 0);
+ DLIB_TEST(a.b[2] == 0);
+ DLIB_TEST(a.b[3] == 1);
+
+ bo.big_to_host(a.val);
+
+ DLIB_TEST(a.b[0] == 1);
+ DLIB_TEST(a.b[1] == 0);
+ DLIB_TEST(a.b[2] == 0);
+ DLIB_TEST(a.b[3] == 0);
+
+ DLIB_TEST(a.val == 1);
+ bo.host_to_network(a.val);
+ DLIB_TEST(a.val == 0x01000000);
+ bo.network_to_host(a.val);
+ DLIB_TEST(a.val == 1);
+ }
+ else
+ {
+ DLIB_TEST(a.b[0] == 0);
+ DLIB_TEST(a.b[1] == 0);
+ DLIB_TEST(a.b[2] == 0);
+ DLIB_TEST(a.b[3] == 1);
+
+ bo.host_to_little(a.val);
+
+ DLIB_TEST(a.b[0] == 1);
+ DLIB_TEST(a.b[1] == 0);
+ DLIB_TEST(a.b[2] == 0);
+ DLIB_TEST(a.b[3] == 0);
+
+ bo.little_to_host(a.val);
+
+ DLIB_TEST(a.b[0] == 0);
+ DLIB_TEST(a.b[1] == 0);
+ DLIB_TEST(a.b[2] == 0);
+ DLIB_TEST(a.b[3] == 1);
+
+
+ DLIB_TEST(a.val == 1);
+ bo.network_to_host(a.val);
+ DLIB_TEST(a.val == 1);
+ bo.host_to_network(a.val);
+ DLIB_TEST(a.val == 1);
+
+ }
+
+
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/cca.cpp b/ml/dlib/dlib/test/cca.cpp
new file mode 100644
index 000000000..a2014121d
--- /dev/null
+++ b/ml/dlib/dlib/test/cca.cpp
@@ -0,0 +1,460 @@
+// Copyright (C) 2013 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <dlib/statistics.h>
+#include <dlib/sparse_vector.h>
+#include <dlib/timing.h>
+#include <map>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.cca");
+
+ dlib::rand rnd;
+// ----------------------------------------------------------------------------------------
+
+ /*
+ std::vector<std::map<unsigned long, double> > make_really_big_test_matrix (
+ )
+ {
+ std::vector<std::map<unsigned long,double> > temp(30000);
+ for (unsigned long i = 0; i < temp.size(); ++i)
+ {
+ for (int k = 0; k < 30; ++k)
+ temp[i][rnd.get_random_32bit_number()%10000] = 1;
+ }
+ return temp;
+ }
+ */
+
+ template <typename T>
+ std::vector<std::map<unsigned long, T> > mat_to_sparse (
+ const matrix<T>& A
+ )
+ {
+ std::vector<std::map<unsigned long,T> > temp(A.nr());
+ for (long r = 0; r < A.nr(); ++r)
+ {
+ for (long c = 0; c < A.nc(); ++c)
+ {
+ temp[r][c] = A(r,c);
+ }
+ }
+ return temp;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename EXP>
+ matrix<typename EXP::type> rm_zeros (
+ const matrix_exp<EXP>& m
+ )
+ {
+ // Do this to avoid trying to correlate super small numbers that are really just
+ // zero. Doing this avoids some potential false alarms in the unit tests below.
+ return round_zeros(m, max(abs(m))*1e-14);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ /*
+ void check_correlation (
+ matrix<double> L,
+ matrix<double> R,
+ const matrix<double>& Ltrans,
+ const matrix<double>& Rtrans,
+ const matrix<double,0,1>& correlations
+ )
+ {
+ // apply the transforms
+ L = L*Ltrans;
+ R = R*Rtrans;
+
+ // compute the real correlation values. Store them in A.
+ matrix<double> A = compute_correlations(L, R);
+
+ for (long i = 0; i < correlations.size(); ++i)
+ {
+ // compare what the measured correlation values are (in A) to the
+ // predicted values.
+ cout << "error: "<< A(i) - correlations(i);
+ }
+ }
+ */
+
+// ----------------------------------------------------------------------------------------
+
+ void test_cca3()
+ {
+ print_spinner();
+ const unsigned long rank = rnd.get_random_32bit_number()%10 + 1;
+ const unsigned long m = rank + rnd.get_random_32bit_number()%15;
+ const unsigned long n = rank + rnd.get_random_32bit_number()%15;
+ const unsigned long n2 = rank + rnd.get_random_32bit_number()%15;
+ const unsigned long rank2 = rank + rnd.get_random_32bit_number()%5;
+
+ dlog << LINFO << "m: " << m;
+ dlog << LINFO << "n: " << n;
+ dlog << LINFO << "n2: " << n2;
+ dlog << LINFO << "rank: " << rank;
+ dlog << LINFO << "rank2: " << rank2;
+
+
+ matrix<double> L = randm(m,rank, rnd)*randm(rank,n, rnd);
+ //matrix<double> R = randm(m,rank, rnd)*randm(rank,n2, rnd);
+ matrix<double> R = L*randm(n,n2, rnd);
+ //matrix<double> L = randm(m,n, rnd);
+ //matrix<double> R = randm(m,n2, rnd);
+
+ matrix<double> Ltrans, Rtrans;
+ matrix<double,0,1> correlations;
+
+ {
+ correlations = cca(L, R, Ltrans, Rtrans, min(m,n), max(n,n2));
+ DLIB_TEST(Ltrans.nc() == Rtrans.nc());
+ dlog << LINFO << "correlations: "<< trans(correlations);
+
+ const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations));
+ dlog << LINFO << "correlation error: "<< corr_error;
+ DLIB_TEST_MSG(corr_error < 1e-13, Ltrans << "\n\n" << Rtrans);
+
+ const double trans_error = max(abs(L*Ltrans - R*Rtrans));
+ dlog << LINFO << "trans_error: "<< trans_error;
+ DLIB_TEST_MSG(trans_error < 1e-9, trans_error);
+ }
+ {
+ correlations = cca(mat_to_sparse(L), mat_to_sparse(R), Ltrans, Rtrans, min(m,n), max(n,n2)+6, 4);
+ DLIB_TEST(Ltrans.nc() == Rtrans.nc());
+ dlog << LINFO << "correlations: "<< trans(correlations);
+ dlog << LINFO << "computed cors: " << trans(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)));
+
+ const double trans_error = max(abs(L*Ltrans - R*Rtrans));
+ dlog << LINFO << "trans_error: "<< trans_error;
+ const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations));
+ dlog << LINFO << "correlation error: "<< corr_error;
+ DLIB_TEST_MSG(corr_error < 1e-13, Ltrans << "\n\n" << Rtrans);
+
+ DLIB_TEST(trans_error < 2e-9);
+ }
+
+ dlog << LINFO << "*****************************************************";
+ }
+
+ void test_cca2()
+ {
+ print_spinner();
+ const unsigned long rank = rnd.get_random_32bit_number()%10 + 1;
+ const unsigned long m = rank + rnd.get_random_32bit_number()%15;
+ const unsigned long n = rank + rnd.get_random_32bit_number()%15;
+ const unsigned long n2 = rank + rnd.get_random_32bit_number()%15;
+
+ dlog << LINFO << "m: " << m;
+ dlog << LINFO << "n: " << n;
+ dlog << LINFO << "n2: " << n2;
+ dlog << LINFO << "rank: " << rank;
+
+
+ matrix<double> L = randm(m,n, rnd);
+ matrix<double> R = randm(m,n2, rnd);
+
+ matrix<double> Ltrans, Rtrans;
+ matrix<double,0,1> correlations;
+
+ {
+ correlations = cca(L, R, Ltrans, Rtrans, min(n,n2), max(n,n2)-min(n,n2));
+ DLIB_TEST(Ltrans.nc() == Rtrans.nc());
+ dlog << LINFO << "correlations: "<< trans(correlations);
+
+ if (Ltrans.nc() > 1)
+ {
+ // The CCA projection directions are supposed to be uncorrelated for
+ // non-matching pairs of projections.
+ const double corr_rot1_error = max(abs(compute_correlations(rm_zeros(L*rotate<0,1>(Ltrans)), rm_zeros(R*Rtrans))));
+ dlog << LINFO << "corr_rot1_error: "<< corr_rot1_error;
+ DLIB_TEST(std::abs(corr_rot1_error) < 1e-10);
+ }
+ // Matching projection directions should be correlated with the amount of
+ // correlation indicated by the return value of cca().
+ const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations));
+ dlog << LINFO << "correlation error: "<< corr_error;
+ DLIB_TEST(corr_error < 1e-13);
+ }
+ {
+ correlations = cca(mat_to_sparse(L), mat_to_sparse(R), Ltrans, Rtrans, min(n,n2), max(n,n2)-min(n,n2));
+ DLIB_TEST(Ltrans.nc() == Rtrans.nc());
+ dlog << LINFO << "correlations: "<< trans(correlations);
+
+ if (Ltrans.nc() > 1)
+ {
+ // The CCA projection directions are supposed to be uncorrelated for
+ // non-matching pairs of projections.
+ const double corr_rot1_error = max(abs(compute_correlations(rm_zeros(L*rotate<0,1>(Ltrans)), rm_zeros(R*Rtrans))));
+ dlog << LINFO << "corr_rot1_error: "<< corr_rot1_error;
+ DLIB_TEST(std::abs(corr_rot1_error) < 1e-10);
+ }
+ // Matching projection directions should be correlated with the amount of
+ // correlation indicated by the return value of cca().
+ const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations));
+ dlog << LINFO << "correlation error: "<< corr_error;
+ DLIB_TEST(corr_error < 1e-13);
+ }
+
+ dlog << LINFO << "*****************************************************";
+ }
+
+ void test_cca1()
+ {
+ print_spinner();
+ const unsigned long rank = rnd.get_random_32bit_number()%10 + 1;
+ const unsigned long m = rank + rnd.get_random_32bit_number()%15;
+ const unsigned long n = rank + rnd.get_random_32bit_number()%15;
+
+ dlog << LINFO << "m: " << m;
+ dlog << LINFO << "n: " << n;
+ dlog << LINFO << "rank: " << rank;
+
+ matrix<double> T = randm(n,n, rnd);
+
+ matrix<double> L = randm(m,rank, rnd)*randm(rank,n, rnd);
+ //matrix<double> L = randm(m,n, rnd);
+ matrix<double> R = L*T;
+
+ matrix<double> Ltrans, Rtrans;
+ matrix<double,0,1> correlations;
+
+ {
+ correlations = cca(L, R, Ltrans, Rtrans, rank);
+ DLIB_TEST(Ltrans.nc() == Rtrans.nc());
+ if (Ltrans.nc() > 1)
+ {
+ // The CCA projection directions are supposed to be uncorrelated for
+ // non-matching pairs of projections.
+ const double corr_rot1_error = max(abs(compute_correlations(rm_zeros(L*rotate<0,1>(Ltrans)), rm_zeros(R*Rtrans))));
+ dlog << LINFO << "corr_rot1_error: "<< corr_rot1_error;
+ DLIB_TEST(std::abs(corr_rot1_error) < 2e-9);
+ }
+ // Matching projection directions should be correlated with the amount of
+ // correlation indicated by the return value of cca().
+ const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations));
+ dlog << LINFO << "correlation error: "<< corr_error;
+ DLIB_TEST(corr_error < 1e-13);
+
+ const double trans_error = max(abs(L*Ltrans - R*Rtrans));
+ dlog << LINFO << "trans_error: "<< trans_error;
+ DLIB_TEST(trans_error < 2e-9);
+
+ dlog << LINFO << "correlations: "<< trans(correlations);
+ }
+ {
+ correlations = cca(mat_to_sparse(L), mat_to_sparse(R), Ltrans, Rtrans, rank);
+ DLIB_TEST(Ltrans.nc() == Rtrans.nc());
+ if (Ltrans.nc() > 1)
+ {
+ // The CCA projection directions are supposed to be uncorrelated for
+ // non-matching pairs of projections.
+ const double corr_rot1_error = max(abs(compute_correlations(rm_zeros(L*rotate<0,1>(Ltrans)), rm_zeros(R*Rtrans))));
+ dlog << LINFO << "corr_rot1_error: "<< corr_rot1_error;
+ DLIB_TEST(std::abs(corr_rot1_error) < 2e-9);
+ }
+ // Matching projection directions should be correlated with the amount of
+ // correlation indicated by the return value of cca().
+ const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations));
+ dlog << LINFO << "correlation error: "<< corr_error;
+ DLIB_TEST(corr_error < 1e-13);
+
+ const double trans_error = max(abs(L*Ltrans - R*Rtrans));
+ dlog << LINFO << "trans_error: "<< trans_error;
+ DLIB_TEST(trans_error < 2e-9);
+
+ dlog << LINFO << "correlations: "<< trans(correlations);
+ }
+
+ dlog << LINFO << "*****************************************************";
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_svd_fast(
+ long rank,
+ long m,
+ long n
+ )
+ {
+ print_spinner();
+ matrix<double> A = randm(m,rank,rnd)*randm(rank,n,rnd);
+ matrix<double> u,v;
+ matrix<double,0,1> w;
+
+ dlog << LINFO << "rank: "<< rank;
+ dlog << LINFO << "m: "<< m;
+ dlog << LINFO << "n: "<< n;
+
+ svd_fast(A, u, w, v, rank, 2);
+ DLIB_TEST(u.nr() == m);
+ DLIB_TEST(u.nc() == rank);
+ DLIB_TEST(w.nr() == rank);
+ DLIB_TEST(w.nc() == 1);
+ DLIB_TEST(v.nr() == n);
+ DLIB_TEST(v.nc() == rank);
+ DLIB_TEST(max(abs(trans(u)*u - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(trans(v)*v - identity_matrix<double>(u.nc()))) < 1e-13);
+
+ DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-13);
+ svd_fast(mat_to_sparse(A), u, w, v, rank, 2);
+ DLIB_TEST(u.nr() == m);
+ DLIB_TEST(u.nc() == rank);
+ DLIB_TEST(w.nr() == rank);
+ DLIB_TEST(w.nc() == 1);
+ DLIB_TEST(v.nr() == n);
+ DLIB_TEST(v.nc() == rank);
+ DLIB_TEST(max(abs(trans(u)*u - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(trans(v)*v - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-13);
+
+ svd_fast(A, u, w, v, rank, 0);
+ DLIB_TEST(u.nr() == m);
+ DLIB_TEST(u.nc() == rank);
+ DLIB_TEST(w.nr() == rank);
+ DLIB_TEST(w.nc() == 1);
+ DLIB_TEST(v.nr() == n);
+ DLIB_TEST(v.nc() == rank);
+ DLIB_TEST(max(abs(trans(u)*u - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(trans(v)*v - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST_MSG(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-9,max(abs(tmp(A - u*diagm(w)*trans(v)))));
+ svd_fast(mat_to_sparse(A), u, w, v, rank, 0);
+ DLIB_TEST(u.nr() == m);
+ DLIB_TEST(u.nc() == rank);
+ DLIB_TEST(w.nr() == rank);
+ DLIB_TEST(w.nc() == 1);
+ DLIB_TEST(v.nr() == n);
+ DLIB_TEST(v.nc() == rank);
+ DLIB_TEST(max(abs(trans(u)*u - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(trans(v)*v - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-10);
+
+ svd_fast(A, u, w, v, rank+5, 0);
+ DLIB_TEST(max(abs(trans(u)*u - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(trans(v)*v - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-11);
+ svd_fast(mat_to_sparse(A), u, w, v, rank+5, 0);
+ DLIB_TEST(max(abs(trans(u)*u - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(trans(v)*v - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-11);
+ svd_fast(A, u, w, v, rank+5, 1);
+ DLIB_TEST(max(abs(trans(u)*u - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(trans(v)*v - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-12);
+ svd_fast(mat_to_sparse(A), u, w, v, rank+5, 1);
+ DLIB_TEST(max(abs(trans(u)*u - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(trans(v)*v - identity_matrix<double>(u.nc()))) < 1e-13);
+ DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-12);
+ }
+
+ void test_svd_fast()
+ {
+ for (int iter = 0; iter < 1000; ++iter)
+ {
+ const unsigned long rank = rnd.get_random_32bit_number()%10 + 1;
+ const unsigned long m = rank + rnd.get_random_32bit_number()%10;
+ const unsigned long n = rank + rnd.get_random_32bit_number()%10;
+
+ test_svd_fast(rank, m, n);
+
+ }
+ test_svd_fast(1, 1, 1);
+ test_svd_fast(1, 2, 2);
+ test_svd_fast(1, 1, 2);
+ test_svd_fast(1, 2, 1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ /*
+ typedef std::vector<std::pair<unsigned int, float>> sv;
+ sv rand_sparse_vector()
+ {
+ static dlib::rand rnd;
+ sv v;
+ for (int i = 0; i < 50; ++i)
+ v.push_back(make_pair(rnd.get_integer(400000), rnd.get_random_gaussian()*100));
+
+ make_sparse_vector_inplace(v);
+ return v;
+ }
+
+ sv rand_basis_combo(const std::vector<sv>& basis)
+ {
+ static dlib::rand rnd;
+ sv result;
+
+ for (int i = 0; i < 5; ++i)
+ {
+ sv temp = basis[rnd.get_integer(basis.size())];
+ scale_by(temp, rnd.get_random_gaussian());
+ result = add(result,temp);
+ }
+ return result;
+ }
+
+ void big_sparse_speed_test()
+ {
+ cout << "making A" << endl;
+ std::vector<sv> basis;
+ for (int i = 0; i < 100; ++i)
+ basis.emplace_back(rand_sparse_vector());
+
+ std::vector<sv> A;
+ for (int i = 0; i < 500000; ++i)
+ A.emplace_back(rand_basis_combo(basis));
+
+ cout << "done making A" << endl;
+
+ matrix<float> u,v;
+ matrix<float,0,1> w;
+ {
+ timing::block aosijdf(0,"call it");
+ svd_fast(A, u,w,v, 100, 5);
+ }
+
+ timing::print();
+ }
+ */
+
+// ----------------------------------------------------------------------------------------
+
+ class test_cca : public tester
+ {
+ public:
+ test_cca (
+ ) :
+ tester ("test_cca",
+ "Runs tests on the cca() and svd_fast() routines.")
+ {}
+
+ void perform_test (
+ )
+ {
+ //big_sparse_speed_test();
+ for (int i = 0; i < 200; ++i)
+ {
+ test_cca1();
+ test_cca2();
+ test_cca3();
+ }
+ test_svd_fast();
+ }
+ } a;
+
+
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/checkerboard.h b/ml/dlib/dlib/test/checkerboard.h
new file mode 100644
index 000000000..90c8f0cb8
--- /dev/null
+++ b/ml/dlib/dlib/test/checkerboard.h
@@ -0,0 +1,55 @@
+#ifndef DLIB_CHECKERBOARD_TeST_H_
+#define DLIB_CHECKERBOARD_TeST_H_
+
+#include <dlib/matrix.h>
+#include <vector>
+#include <dlib/rand.h>
+
+namespace dlib
+{
+
+ template <typename scalar_type>
+ void get_checkerboard_problem (
+ std::vector<matrix<scalar_type,2,1> >& x,
+ std::vector<scalar_type>& y,
+ const long num_samples,
+ const long board_dimension = 8
+ )
+ /*!
+ requires
+ - num_samples > 0
+ - board_dimension > 0
+ ensures
+ - #x.size() == y.size() == num_samples
+ - is_binary_classification_problem(#x,#y) == true
+ - #x will contain points and #y labels that were
+ sampled randomly from a checkers board that has
+ board_dimension squares on each side.
+ !*/
+ {
+ static dlib::rand rnd;
+
+ x.clear();
+ y.clear();
+
+ matrix<scalar_type,2,1> sample;
+ for (long i = 0; i < num_samples; ++i)
+ {
+ sample(0) = rnd.get_random_double();
+ sample(1) = rnd.get_random_double();
+ sample *= board_dimension;
+
+ x.push_back(sample);
+ if (((int)sum(floor(sample)) %2) == 0)
+ y.push_back(+1);
+ else
+ y.push_back(-1);
+
+ }
+ }
+
+
+}
+
+#endif // DLIB_CHECKERBOARD_TeST_H_
+
diff --git a/ml/dlib/dlib/test/clustering.cpp b/ml/dlib/dlib/test/clustering.cpp
new file mode 100644
index 000000000..a784c57c0
--- /dev/null
+++ b/ml/dlib/dlib/test/clustering.cpp
@@ -0,0 +1,410 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <dlib/clustering.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.clustering");
+
+// ----------------------------------------------------------------------------------------
+
+ void make_test_graph(
+ dlib::rand& rnd,
+ std::vector<sample_pair>& edges,
+ std::vector<unsigned long>& labels,
+ const int groups,
+ const int group_size,
+ const int noise_level,
+ const double missed_edges
+ )
+ {
+ labels.resize(groups*group_size);
+
+ for (unsigned long i = 0; i < labels.size(); ++i)
+ {
+ labels[i] = i/group_size;
+ }
+
+ edges.clear();
+ for (int i = 0; i < groups; ++i)
+ {
+ for (int j = 0; j < group_size; ++j)
+ {
+ for (int k = 0; k < group_size; ++k)
+ {
+ if (j == k)
+ continue;
+
+ if (rnd.get_random_double() < missed_edges)
+ continue;
+
+ edges.push_back(sample_pair(j+group_size*i, k+group_size*i, 1));
+ }
+ }
+ }
+
+ for (int k = 0; k < groups*noise_level; ++k)
+ {
+ const int i = rnd.get_random_32bit_number()%labels.size();
+ const int j = rnd.get_random_32bit_number()%labels.size();
+ edges.push_back(sample_pair(i,j,1));
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void make_modularity_matrices (
+ const std::vector<sample_pair>& edges,
+ matrix<double>& A,
+ matrix<double>& P,
+ double& m
+ )
+ {
+ const unsigned long num_nodes = max_index_plus_one(edges);
+ A.set_size(num_nodes, num_nodes);
+ P.set_size(num_nodes, num_nodes);
+ A = 0;
+ P = 0;
+ std::vector<double> k(num_nodes,0);
+
+ for (unsigned long i = 0; i < edges.size(); ++i)
+ {
+ const unsigned long n1 = edges[i].index1();
+ const unsigned long n2 = edges[i].index2();
+ k[n1] += edges[i].distance();
+ if (n1 != n2)
+ {
+ k[n2] += edges[i].distance();
+ A(n2,n1) += edges[i].distance();
+ }
+
+ A(n1,n2) += edges[i].distance();
+ }
+
+ m = sum(A)/2;
+
+ for (long r = 0; r < P.nr(); ++r)
+ {
+ for (long c = 0; c < P.nc(); ++c)
+ {
+ P(r,c) = k[r]*k[c]/(2*m);
+ }
+ }
+
+ }
+
+ double compute_modularity_simple (
+ const std::vector<sample_pair>& edges,
+ std::vector<unsigned long> labels
+ )
+ {
+ double m;
+ matrix<double> A,P;
+ make_modularity_matrices(edges, A, P, m);
+ matrix<double> B = A - P;
+
+ double Q = 0;
+ for (long r = 0; r < B.nr(); ++r)
+ {
+ for (long c = 0; c < B.nc(); ++c)
+ {
+ if (labels[r] == labels[c])
+ {
+ Q += B(r,c);
+ }
+ }
+ }
+ return 1.0/(2*m) * Q;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_modularity(dlib::rand& rnd)
+ {
+ print_spinner();
+ std::vector<sample_pair> edges;
+ std::vector<ordered_sample_pair> oedges;
+ std::vector<unsigned long> labels;
+
+ make_test_graph(rnd, edges, labels, 10, 30, 3, 0.10);
+ if (rnd.get_random_double() < 0.5)
+ remove_duplicate_edges(edges);
+ convert_unordered_to_ordered(edges, oedges);
+
+
+ const double m1 = modularity(edges, labels);
+ const double m2 = compute_modularity_simple(edges, labels);
+ const double m3 = modularity(oedges, labels);
+
+ DLIB_TEST(std::abs(m1-m2) < 1e-12);
+ DLIB_TEST(std::abs(m2-m3) < 1e-12);
+ DLIB_TEST(std::abs(m3-m1) < 1e-12);
+ }
+
+ void test_newman_clustering(dlib::rand& rnd)
+ {
+ print_spinner();
+ std::vector<sample_pair> edges;
+ std::vector<unsigned long> labels;
+
+ make_test_graph(rnd, edges, labels, 5, 30, 3, 0.10);
+ if (rnd.get_random_double() < 0.5)
+ remove_duplicate_edges(edges);
+
+
+ std::vector<unsigned long> labels2;
+
+ unsigned long num_clusters = newman_cluster(edges, labels2);
+ DLIB_TEST(labels.size() == labels2.size());
+ DLIB_TEST(num_clusters == 5);
+
+ for (unsigned long i = 0; i < labels.size(); ++i)
+ {
+ for (unsigned long j = 0; j < labels.size(); ++j)
+ {
+ if (labels[i] == labels[j])
+ {
+ DLIB_TEST(labels2[i] == labels2[j]);
+ }
+ else
+ {
+ DLIB_TEST(labels2[i] != labels2[j]);
+ }
+ }
+ }
+ }
+
+ void test_chinese_whispers(dlib::rand& rnd)
+ {
+ print_spinner();
+ std::vector<sample_pair> edges;
+ std::vector<unsigned long> labels;
+
+ make_test_graph(rnd, edges, labels, 5, 30, 3, 0.10);
+ if (rnd.get_random_double() < 0.5)
+ remove_duplicate_edges(edges);
+
+
+ std::vector<unsigned long> labels2;
+
+ unsigned long num_clusters;
+ if (rnd.get_random_double() < 0.5)
+ num_clusters = chinese_whispers(edges, labels2, 200, rnd);
+ else
+ num_clusters = chinese_whispers(edges, labels2);
+
+ DLIB_TEST(labels.size() == labels2.size());
+ DLIB_TEST(num_clusters == 5);
+
+ for (unsigned long i = 0; i < labels.size(); ++i)
+ {
+ for (unsigned long j = 0; j < labels.size(); ++j)
+ {
+ if (labels[i] == labels[j])
+ {
+ DLIB_TEST(labels2[i] == labels2[j]);
+ }
+ else
+ {
+ DLIB_TEST(labels2[i] != labels2[j]);
+ }
+ }
+ }
+ }
+
+ void test_bottom_up_clustering()
+ {
+ std::vector<dpoint> pts;
+ pts.push_back(dpoint(0.0,0.0));
+ pts.push_back(dpoint(0.5,0.0));
+ pts.push_back(dpoint(0.5,0.5));
+ pts.push_back(dpoint(0.0,0.5));
+
+ pts.push_back(dpoint(3.0,3.0));
+ pts.push_back(dpoint(3.5,3.0));
+ pts.push_back(dpoint(3.5,3.5));
+ pts.push_back(dpoint(3.0,3.5));
+
+ pts.push_back(dpoint(7.0,7.0));
+ pts.push_back(dpoint(7.5,7.0));
+ pts.push_back(dpoint(7.5,7.5));
+ pts.push_back(dpoint(7.0,7.5));
+
+ matrix<double> dists(pts.size(), pts.size());
+ for (long r = 0; r < dists.nr(); ++r)
+ for (long c = 0; c < dists.nc(); ++c)
+ dists(r,c) = length(pts[r]-pts[c]);
+
+
+ matrix<unsigned long,0,1> truth(12);
+ truth = 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2, 2, 2, 2;
+
+ std::vector<unsigned long> labels;
+ DLIB_TEST(bottom_up_cluster(dists, labels, 3) == 3);
+ DLIB_TEST(mat(labels) == truth);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1, 4.0) == 3);
+ DLIB_TEST(mat(labels) == truth);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1, 4.95) == 2);
+ truth = 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 1, 1, 1, 1;
+ DLIB_TEST(mat(labels) == truth);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1) == 1);
+ truth = 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0;
+ DLIB_TEST(mat(labels) == truth);
+
+ dists.set_size(0,0);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 3) == 0);
+ DLIB_TEST(labels.size() == 0);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1) == 0);
+ DLIB_TEST(labels.size() == 0);
+
+ dists.set_size(1,1);
+ dists = 1;
+ DLIB_TEST(bottom_up_cluster(dists, labels, 3) == 1);
+ DLIB_TEST(labels.size() == 1);
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1) == 1);
+ DLIB_TEST(labels.size() == 1);
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1, 0) == 1);
+ DLIB_TEST(labels.size() == 1);
+ DLIB_TEST(labels[0] == 0);
+
+ dists.set_size(2,2);
+ dists = 1;
+ DLIB_TEST(bottom_up_cluster(dists, labels, 3) == 2);
+ DLIB_TEST(labels.size() == 2);
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(labels[1] == 1);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1) == 1);
+ DLIB_TEST(labels.size() == 2);
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(labels[1] == 0);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1, 1) == 1);
+ DLIB_TEST(labels.size() == 2);
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(labels[1] == 0);
+ DLIB_TEST(bottom_up_cluster(dists, labels, 1, 0.999) == 2);
+ DLIB_TEST(labels.size() == 2);
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(labels[1] == 1);
+ }
+
+ void test_segment_number_line()
+ {
+ dlib::rand rnd;
+
+
+ std::vector<double> x;
+ for (int i = 0; i < 5000; ++i)
+ {
+ x.push_back(rnd.get_double_in_range(-1.5, -1.01));
+ x.push_back(rnd.get_double_in_range(-0.99, -0.01));
+ x.push_back(rnd.get_double_in_range(0.01, 1));
+ }
+
+ auto r = segment_number_line(x,1);
+ std::sort(r.begin(), r.end());
+ DLIB_TEST(r.size() == 3);
+ DLIB_TEST(-1.5 <= r[0].lower && r[0].lower < r[0].upper && r[0].upper <= -1.01);
+ DLIB_TEST(-0.99 <= r[1].lower && r[1].lower < r[1].upper && r[1].upper <= -0.01);
+ DLIB_TEST(0.01 <= r[2].lower && r[2].lower < r[2].upper && r[2].upper <= 1);
+
+ x.clear();
+ for (int i = 0; i < 5000; ++i)
+ {
+ x.push_back(rnd.get_double_in_range(-2, 1));
+ x.push_back(rnd.get_double_in_range(-2, 1));
+ x.push_back(rnd.get_double_in_range(-2, 1));
+ }
+
+ r = segment_number_line(x,1);
+ DLIB_TEST(r.size() == 3);
+ r = segment_number_line(x,1.5);
+ DLIB_TEST(r.size() == 2);
+ r = segment_number_line(x,10.5);
+ DLIB_TEST(r.size() == 1);
+ DLIB_TEST(-2 <= r[0].lower && r[0].lower < r[0].upper && r[0].upper <= 1);
+ }
+
+ class test_clustering : public tester
+ {
+ public:
+ test_clustering (
+ ) :
+ tester ("test_clustering",
+ "Runs tests on the clustering routines.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_bottom_up_clustering();
+ test_segment_number_line();
+
+ dlib::rand rnd;
+
+ std::vector<sample_pair> edges;
+ std::vector<unsigned long> labels;
+ DLIB_TEST(newman_cluster(edges, labels) == 0);
+ DLIB_TEST(chinese_whispers(edges, labels) == 0);
+
+ edges.push_back(sample_pair(0,1,1));
+ DLIB_TEST(newman_cluster(edges, labels) == 1);
+ DLIB_TEST(labels.size() == 2);
+ DLIB_TEST(chinese_whispers(edges, labels) == 1);
+ DLIB_TEST(labels.size() == 2);
+
+ edges.clear();
+ edges.push_back(sample_pair(0,0,1));
+ DLIB_TEST(newman_cluster(edges, labels) == 1);
+ DLIB_TEST(labels.size() == 1);
+ DLIB_TEST(chinese_whispers(edges, labels) == 1);
+ DLIB_TEST(labels.size() == 1);
+
+ edges.clear();
+ edges.push_back(sample_pair(1,1,1));
+ DLIB_TEST(newman_cluster(edges, labels) == 1);
+ DLIB_TEST(labels.size() == 2);
+ DLIB_TEST(chinese_whispers(edges, labels) == 2);
+ DLIB_TEST(labels.size() == 2);
+
+ edges.push_back(sample_pair(0,0,1));
+ DLIB_TEST(newman_cluster(edges, labels) == 2);
+ DLIB_TEST(labels.size() == 2);
+ DLIB_TEST(chinese_whispers(edges, labels) == 2);
+ DLIB_TEST(labels.size() == 2);
+
+
+ for (int i = 0; i < 10; ++i)
+ test_modularity(rnd);
+
+ for (int i = 0; i < 10; ++i)
+ test_newman_clustering(rnd);
+
+ for (int i = 0; i < 10; ++i)
+ test_chinese_whispers(rnd);
+
+
+ }
+ } a;
+
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/cmd_line_parser.cpp b/ml/dlib/dlib/test/cmd_line_parser.cpp
new file mode 100644
index 000000000..9216a76cc
--- /dev/null
+++ b/ml/dlib/dlib/test/cmd_line_parser.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <string>
+#include <dlib/string.h>
+
+#include <dlib/cmd_line_parser.h>
+
+#include "tester.h"
+
+#include "cmd_line_parser.h"
+namespace
+{
+
+ class cmd_line_parser_tester : public tester
+ {
+ public:
+ cmd_line_parser_tester (
+ ) :
+ tester ("test_cmd_line_parser_char",
+ "Runs tests on the cmd_line_parser component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a with char";
+ cmd_line_parser_kernel_test<cmd_line_parser<char>::kernel_1a>();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_1a_c with char";
+ cmd_line_parser_kernel_test<cmd_line_parser<char>::kernel_1a_c>();
+ print_spinner();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/cmd_line_parser.h b/ml/dlib/dlib/test/cmd_line_parser.h
new file mode 100644
index 000000000..6f8e411a4
--- /dev/null
+++ b/ml/dlib/dlib/test/cmd_line_parser.h
@@ -0,0 +1,901 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_CMD_LINE_PARSER_KERNEl_TEST_H_
+#define DLIB_CMD_LINE_PARSER_KERNEl_TEST_H_
+
+
+#include <string>
+#include <dlib/string.h>
+
+#include <dlib/cmd_line_parser.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.cmd_line_parser");
+
+ template <
+ typename clp
+ >
+ void cmd_line_parser_kernel_test (
+ )
+ /*!
+ requires
+ - clp is an implementation of cmd_line_parser_kernel_abstract.h
+ ensures
+ - runs tests on clp for compliance with the specs
+ !*/
+ {
+ typedef typename clp::char_type ct;
+
+
+
+
+ int argc;
+ const ct* argv[100];
+ bool ok;
+
+ for (int j = 0; j < 3; ++j)
+ {
+ clp test, test2;
+
+
+
+
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start());
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+
+ DLIB_TEST(test.parsed_line() == false);
+ DLIB_TEST(test.option_is_defined(_dT(ct,"a")) == false);
+ DLIB_TEST(test.option_is_defined(_dT(ct,"a")) == false);
+ DLIB_TEST(test.option_is_defined(_dT(ct,"a")) == false);
+
+ DLIB_TEST(test.parsed_line() == false);
+ DLIB_TEST(test.option_is_defined(_dT(ct,"a")) == false);
+ DLIB_TEST(test.option_is_defined(_dT(ct,"b")) == false);
+ DLIB_TEST(test.option_is_defined(_dT(ct,"\0")) == false);
+
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+
+ // program arg1 --davis arg2 -cZzarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis");
+ argv[3] = _dT(ct,"arg2");
+ argv[4] = _dT(ct,"-cZzarg");
+ argv[5] = _dT(ct,"asdf");
+ argc = 6;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"));
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ try { test.parse(argc,argv); }
+ catch (error& e)
+ {
+ DLIB_TEST_MSG(false,e.info);
+ }
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"));
+ DLIB_TEST(test.option(_dT(ct,"c")).name() == _dT(ct,"c"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).number_of_arguments() == 0);
+ DLIB_TEST(test.option(_dT(ct,"c")).number_of_arguments() == 0);
+ DLIB_TEST(test.option(_dT(ct,"Z")).number_of_arguments() == 2);
+ DLIB_TEST(test.number_of_arguments() == 2);
+ DLIB_TEST(test[0] == _dT(ct,"arg1"));
+ DLIB_TEST(test[1] == _dT(ct,"arg2"));
+ DLIB_TEST(test.option(_dT(ct,"d")).count()==0);
+ DLIB_TEST(test.option(_dT(ct,"davis")).count()==1);
+ DLIB_TEST_MSG(test.option(_dT(ct,"c")).count()==1,test.option(_dT(ct,"c")).count());
+ DLIB_TEST(test.option(_dT(ct,"Z")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"));
+
+ }
+
+
+
+ swap(test,test2);
+
+
+
+
+
+ // program arg1 --davis arg2 -cZ zarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis");
+ argv[3] = _dT(ct,"arg2");
+ argv[4] = _dT(ct,"-cZ");
+ argv[5] = _dT(ct,"zarg");
+ argv[6] = _dT(ct,"asdf");
+ argc = 7;
+
+
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ try { test2.parse(argc,argv); }
+ catch (error& e)
+ {
+ DLIB_TEST_MSG(false,e.info);
+ }
+
+ DLIB_TEST(test2.option(_dT(ct,"davis")).name() == _dT(ct,"davis"));
+ DLIB_TEST(test2.option(_dT(ct,"c")).name() == _dT(ct,"c"));
+ DLIB_TEST(test2.option(_dT(ct,"Z")).name() == _dT(ct,"Z"));
+ DLIB_TEST(test2.option(_dT(ct,"davis")).number_of_arguments() == 0);
+ DLIB_TEST(test2.option(_dT(ct,"c")).number_of_arguments() == 0);
+ DLIB_TEST(test2.option(_dT(ct,"Z")).number_of_arguments() == 2);
+ DLIB_TEST(test2.number_of_arguments() == 2);
+ DLIB_TEST(test2[0] == _dT(ct,"arg1"));
+ DLIB_TEST(test2[1] == _dT(ct,"arg2"));
+ DLIB_TEST(test2.option(_dT(ct,"d")).count()==0);
+ DLIB_TEST(test2.option(_dT(ct,"davis")).count()==1);
+ DLIB_TEST(test2.option(_dT(ct,"c")).count()==1);
+ DLIB_TEST(test2.option(_dT(ct,"Z")).count()==1);
+ DLIB_TEST(test2.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"));
+ DLIB_TEST_MSG(test2.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"),
+ narrow(_dT(ct,"*") + test2.option(_dT(ct,"Z")).argument(0,0) + _dT(ct,"*")));
+
+
+ }
+
+
+
+
+
+ // program arg1 --davis= darg darg2 arg2 -cZzarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis=");
+ argv[3] = _dT(ct,"darg");
+ argv[4] = _dT(ct,"darg2");
+ argv[5] = _dT(ct,"arg2");
+ argv[6] = _dT(ct,"-cZzarg");
+ argv[7] = _dT(ct,"asdf");
+ argc = 8;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 2);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ try { test.parse(argc,argv); }
+ catch (error& e)
+ {
+ DLIB_TEST_MSG(false,e.info);
+ }
+
+ DLIB_TEST(test.parsed_line());
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ if (test.element().name() == _dT(ct,"d"))
+ {
+ DLIB_TEST(test.element().count() == 0);
+ }
+ else
+ {
+ DLIB_TEST(test.element().count() == 1);
+ }
+
+ }
+ DLIB_TEST_MSG(count == 4,count);
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"));
+ DLIB_TEST(test.option(_dT(ct,"c")).name() == _dT(ct,"c"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).number_of_arguments() == 2);
+ DLIB_TEST(test.option(_dT(ct,"c")).number_of_arguments() == 0);
+ DLIB_TEST(test.option(_dT(ct,"Z")).number_of_arguments() == 2);
+ DLIB_TEST(test.number_of_arguments() == 2);
+ DLIB_TEST(test[0] == _dT(ct,"arg1"));
+ DLIB_TEST(test[1] == _dT(ct,"arg2"));
+ DLIB_TEST(test.option(_dT(ct,"d")).count()==0);
+ DLIB_TEST(test.option(_dT(ct,"davis")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"c")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).argument(0,0) == _dT(ct,"darg"));
+ DLIB_TEST_MSG(test.option(_dT(ct,"davis")).argument(1,0) == _dT(ct,"darg2"),
+ narrow(test.option(_dT(ct,"davis")).argument(1,0)));
+ }
+
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+
+
+
+
+
+
+ // program arg1 --dav-is=darg darg2 arg2 -cZzarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--dav-is=darg");
+ argv[3] = _dT(ct,"darg2");
+ argv[4] = _dT(ct,"arg2");
+ argv[5] = _dT(ct,"-cZzarg");
+ argv[6] = _dT(ct,"asdf");
+ argc = 7;
+
+
+ test.add_option(_dT(ct,"dav-is"),_dT(ct,"davis option"), 2);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ try { test.parse(argc,argv); }
+ catch (error& e)
+ {
+ DLIB_TEST_MSG(false,e.info);
+ }
+
+ DLIB_TEST(test.parsed_line());
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ if (test.element().name() == _dT(ct,"d"))
+ {
+ DLIB_TEST(test.element().count() == 0);
+ }
+ else
+ {
+ DLIB_TEST(test.element().count() == 1);
+ }
+
+ }
+ DLIB_TEST_MSG(count == 4,count);
+
+ DLIB_TEST(test.option(_dT(ct,"dav-is")).name() == _dT(ct,"dav-is"));
+ DLIB_TEST(test.option(_dT(ct,"c")).name() == _dT(ct,"c"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"));
+ DLIB_TEST(test.option(_dT(ct,"dav-is")).number_of_arguments() == 2);
+ DLIB_TEST(test.option(_dT(ct,"c")).number_of_arguments() == 0);
+ DLIB_TEST(test.option(_dT(ct,"Z")).number_of_arguments() == 2);
+ DLIB_TEST(test.number_of_arguments() == 2);
+ DLIB_TEST(test[0] == _dT(ct,"arg1"));
+ DLIB_TEST(test[1] == _dT(ct,"arg2"));
+ DLIB_TEST(test.option(_dT(ct,"d")).count()==0);
+ DLIB_TEST(test.option(_dT(ct,"dav-is")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"c")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"));
+ DLIB_TEST(test.option(_dT(ct,"dav-is")).argument(0,0) == _dT(ct,"darg"));
+ DLIB_TEST_MSG(test.option(_dT(ct,"dav-is")).argument(1,0) == _dT(ct,"darg2"),
+ narrow(test.option(_dT(ct,"dav-is")).argument(1,0)));
+ }
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+
+
+
+
+
+
+ // program arg1 --davis=darg darg2 arg2 -cZzarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis=darg");
+ argv[3] = _dT(ct,"darg2");
+ argv[4] = _dT(ct,"arg2");
+ argv[5] = _dT(ct,"-cZzarg");
+ argv[6] = _dT(ct,"asdf");
+ argc = 7;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 2);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ try { test.parse(argc,argv); }
+ catch (error& e)
+ {
+ DLIB_TEST_MSG(false,e.info);
+ }
+
+ DLIB_TEST(test.parsed_line());
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ if (test.element().name() == _dT(ct,"d"))
+ {
+ DLIB_TEST(test.element().count() == 0);
+ }
+ else
+ {
+ DLIB_TEST(test.element().count() == 1);
+ }
+
+ }
+ DLIB_TEST_MSG(count == 4,count);
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"));
+ DLIB_TEST(test.option(_dT(ct,"c")).name() == _dT(ct,"c"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).number_of_arguments() == 2);
+ DLIB_TEST(test.option(_dT(ct,"c")).number_of_arguments() == 0);
+ DLIB_TEST(test.option(_dT(ct,"Z")).number_of_arguments() == 2);
+ DLIB_TEST(test.number_of_arguments() == 2);
+ DLIB_TEST(test[0] == _dT(ct,"arg1"));
+ DLIB_TEST(test[1] == _dT(ct,"arg2"));
+ DLIB_TEST(test.option(_dT(ct,"d")).count()==0);
+ DLIB_TEST(test.option(_dT(ct,"davis")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"c")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).argument(0,0) == _dT(ct,"darg"));
+ DLIB_TEST_MSG(test.option(_dT(ct,"davis")).argument(1,0) == _dT(ct,"darg2"),
+ narrow(test.option(_dT(ct,"davis")).argument(1,0)));
+ }
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+
+
+
+
+
+
+ // program arg1 --davis=darg arg2 -cZzarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis=darg");
+ argv[3] = _dT(ct,"arg2");
+ argv[4] = _dT(ct,"-cZzarg");
+ argv[5] = _dT(ct,"asdf");
+ argc = 6;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ try { test.parse(argc,argv); }
+ catch (error& e)
+ {
+ DLIB_TEST_MSG(false,e.info);
+ }
+
+ DLIB_TEST(test.parsed_line());
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ if (test.element().name() == _dT(ct,"d"))
+ {
+ DLIB_TEST(test.element().count() == 0);
+ }
+ else
+ {
+ DLIB_TEST(test.element().count() == 1);
+ }
+
+ }
+ DLIB_TEST_MSG(count == 4,count);
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"));
+ DLIB_TEST(test.option(_dT(ct,"c")).name() == _dT(ct,"c"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).number_of_arguments() == 1);
+ DLIB_TEST(test.option(_dT(ct,"c")).number_of_arguments() == 0);
+ DLIB_TEST(test.option(_dT(ct,"Z")).number_of_arguments() == 2);
+ DLIB_TEST(test.number_of_arguments() == 2);
+ DLIB_TEST(test[0] == _dT(ct,"arg1"));
+ DLIB_TEST(test[1] == _dT(ct,"arg2"));
+ DLIB_TEST(test.option(_dT(ct,"d")).count()==0);
+ DLIB_TEST(test.option(_dT(ct,"davis")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"c")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).argument(0,0) == _dT(ct,"darg"));
+ }
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+
+
+
+
+
+ // program arg1 --davis darg arg2 -cZzarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis");
+ argv[3] = _dT(ct,"darg");
+ argv[4] = _dT(ct,"arg2");
+ argv[5] = _dT(ct,"-cZzarg");
+ argv[6] = _dT(ct,"asdf");
+ argc = 7;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ try { test.parse(argc,argv); }
+ catch (error& e)
+ {
+ DLIB_TEST_MSG(false,e.info);
+ }
+
+ DLIB_TEST(test.parsed_line());
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ if (test.element().name() == _dT(ct,"d"))
+ {
+ DLIB_TEST(test.element().count() == 0);
+ }
+ else
+ {
+ DLIB_TEST(test.element().count() == 1);
+ }
+
+ }
+ DLIB_TEST_MSG(count == 4,count);
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"));
+ DLIB_TEST(test.option(_dT(ct,"c")).name() == _dT(ct,"c"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).number_of_arguments() == 1);
+ DLIB_TEST(test.option(_dT(ct,"c")).number_of_arguments() == 0);
+ DLIB_TEST(test.option(_dT(ct,"Z")).number_of_arguments() == 2);
+ DLIB_TEST(test.number_of_arguments() == 2);
+ DLIB_TEST(test[0] == _dT(ct,"arg1"));
+ DLIB_TEST(test[1] == _dT(ct,"arg2"));
+ DLIB_TEST(test.option(_dT(ct,"d")).count()==0);
+ DLIB_TEST(test.option(_dT(ct,"davis")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"c")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(1) == _dT(ct,"asdf"));
+ DLIB_TEST(test.option(_dT(ct,"davis")).argument(0,0) == _dT(ct,"darg"));
+ }
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+ // this string is incorrect because there is no avis option
+ // program arg1 --avis darg arg2 -cZzarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--avis");
+ argv[3] = _dT(ct,"darg");
+ argv[4] = _dT(ct,"arg2");
+ argv[5] = _dT(ct,"-cZzarg");
+ argv[6] = _dT(ct,"asdf");
+ argc = 7;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ ok = false;
+ try { test.parse(argc,argv); }
+ catch (typename clp::cmd_line_parse_error& e)
+ {
+ DLIB_TEST(e.type == EINVALID_OPTION);
+ DLIB_TEST(e.item == _dT(ct,"avis"));
+ ok = true;
+ }
+ DLIB_TEST(ok);
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+ // the c argument appears twice. make sure its count is correct
+ // program arg1 --davis darg arg2 -ccZzarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis");
+ argv[3] = _dT(ct,"darg");
+ argv[4] = _dT(ct,"arg2");
+ argv[5] = _dT(ct,"-ccZ");
+ argv[6] = _dT(ct,"zarg");
+ argv[7] = _dT(ct,"asdf");
+ argc = 8;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ ok = false;
+ test.parse(argc,argv);
+
+ DLIB_TEST(test.option(_dT(ct,"c")).count()==2);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+ // this is a bad line because the davis argument requires 2 arguments but
+ // only gets one.
+ // program arg1 --davis darg darg2 --davis zarg
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis");
+ argv[3] = _dT(ct,"darg");
+ argv[4] = _dT(ct,"darg2");
+ argv[5] = _dT(ct,"--davis");
+ argv[6] = _dT(ct,"zarg");
+ argc = 7;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 2);
+ test.add_option(_dT(ct,"b"),_dT(ct,"b option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).description() == _dT(ct,"davis option"));
+ DLIB_TEST(test.option(_dT(ct,"b")).description() == _dT(ct,"b option"));
+ DLIB_TEST(test.option(_dT(ct,"d")).description() == _dT(ct,"d option"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).description() == _dT(ct,"Z option"));
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ ok = false;
+ try { test.parse(argc,argv); }
+ catch (typename clp::cmd_line_parse_error& e)
+ {
+ DLIB_TEST(e.type == ETOO_FEW_ARGS);
+ DLIB_TEST(e.num == 2);
+ DLIB_TEST(e.item == _dT(ct,"davis"));
+ ok = true;
+ }
+ DLIB_TEST(ok);
+
+
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ DLIB_TEST(test.element().count() == 0);
+ DLIB_TEST(test.option_is_defined(test.element().name()));
+ }
+ DLIB_TEST_MSG(count == 4,count);
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+ // this is a bad line because the davis argument is not defined
+ // program arg1 --davis darg arg2 -davis zarg asdf
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis");
+ argv[3] = _dT(ct,"darg");
+ argv[4] = _dT(ct,"arg2");
+ argv[5] = _dT(ct,"--davis");
+ argv[6] = _dT(ct,"zarg");
+ argv[7] = _dT(ct,"asdf");
+ argc = 8;
+
+
+ DLIB_TEST(std::basic_string<ct>(argv[0]) == _dT(ct,"program"));
+
+ test.add_option(_dT(ct,"mavis"),_dT(ct,"mavis option"), 1);
+ test.add_option(_dT(ct,"b"),_dT(ct,"b option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ DLIB_TEST(test.option(_dT(ct,"mavis")).description() == _dT(ct,"mavis option"));
+ DLIB_TEST(test.option(_dT(ct,"b")).description() == _dT(ct,"b option"));
+ DLIB_TEST(test.option(_dT(ct,"d")).description() == _dT(ct,"d option"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).description() == _dT(ct,"Z option"));
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ ok = false;
+ try { test.parse(argc,argv); }
+ catch (typename clp::cmd_line_parse_error& e)
+ {
+ DLIB_TEST(e.type == EINVALID_OPTION);
+ DLIB_TEST(e.item == _dT(ct,"davis"));
+ ok = true;
+ }
+ DLIB_TEST(ok);
+
+
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ DLIB_TEST(test.element().count() == 0);
+ DLIB_TEST(test.option_is_defined(test.element().name()));
+ }
+ DLIB_TEST_MSG(count == 4,count);
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+
+ argv[0] = _dT(ct,"program");
+ argc = 1;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2);
+
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).description() == _dT(ct,"davis option"));
+ DLIB_TEST(test.option(_dT(ct,"c")).description() == _dT(ct,"c option"));
+ DLIB_TEST(test.option(_dT(ct,"d")).description() == _dT(ct,"d option"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).description() == _dT(ct,"Z option"));
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ test.parse(argc,argv);
+
+
+ DLIB_TEST(test.number_of_arguments() == 0);
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ DLIB_TEST(test.element().count() == 0);
+ DLIB_TEST(test.option_is_defined(test.element().name()));
+ }
+ DLIB_TEST_MSG(count == 4,count);
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ test.clear();
+
+ // this is to make sure the -- command works right
+ // program arg1 --davis -darg -- arg2 -c asdf -Zeat -Zat -Zjoe's
+ argv[0] = _dT(ct,"program");
+ argv[1] = _dT(ct,"arg1");
+ argv[2] = _dT(ct,"--davis");
+ argv[3] = _dT(ct,"-darg");
+ argv[4] = _dT(ct,"-Zeat");
+ argv[5] = _dT(ct,"-Zat");
+ argv[6] = _dT(ct,"-Zjoe's");
+ argv[7] = _dT(ct,"--");
+ argv[8] = _dT(ct,"arg2");
+ argv[9] = _dT(ct,"-c");
+ argv[10] = _dT(ct,"asdf");
+
+ argc = 11;
+
+
+ test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1);
+ test.add_option(_dT(ct,"c"),_dT(ct,"c option"));
+ test.add_option(_dT(ct,"d"),_dT(ct,"d option"));
+ test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),1);
+
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).description() == _dT(ct,"davis option"));
+ DLIB_TEST(test.option(_dT(ct,"c")).description() == _dT(ct,"c option"));
+ DLIB_TEST(test.option(_dT(ct,"d")).description() == _dT(ct,"d option"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).description() == _dT(ct,"Z option"));
+
+ for (int k = 0; k < 5; ++k)
+ {
+
+ test.parse(argc,argv);
+
+ DLIB_TEST_MSG(test.number_of_arguments() == 4,test.number_of_arguments());
+ DLIB_TEST(test[0] == _dT(ct,"arg1"));
+ DLIB_TEST(test[1] == _dT(ct,"arg2"));
+ DLIB_TEST(test[2] == _dT(ct,"-c"));
+ DLIB_TEST(test[3] == _dT(ct,"asdf"));
+
+ DLIB_TEST(test.option(_dT(ct,"davis")).count()==1);
+ DLIB_TEST(test.option(_dT(ct,"davis")).argument() == _dT(ct,"-darg"));
+ DLIB_TEST(test.option(_dT(ct,"c")).count()==0);
+ DLIB_TEST(test.option(_dT(ct,"d")).count()==0);
+ DLIB_TEST(test.option(_dT(ct,"Z")).count()==3);
+
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"eat"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,1) == _dT(ct,"at"));
+ DLIB_TEST(test.option(_dT(ct,"Z")).argument(0,2) == _dT(ct,"joe's"));
+
+
+ }
+
+
+ }
+ }
+
+}
+
+
+#endif // DLIB_CMD_LINE_PARSER_KERNEl_TEST_H_
+
diff --git a/ml/dlib/dlib/test/cmd_line_parser_wchar_t.cpp b/ml/dlib/dlib/test/cmd_line_parser_wchar_t.cpp
new file mode 100644
index 000000000..f771eeedb
--- /dev/null
+++ b/ml/dlib/dlib/test/cmd_line_parser_wchar_t.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <string>
+#include <dlib/string.h>
+
+#include <dlib/cmd_line_parser.h>
+
+#include "tester.h"
+
+#include "cmd_line_parser.h"
+namespace
+{
+
+ class cmd_line_parser_tester : public tester
+ {
+ public:
+ cmd_line_parser_tester (
+ ) :
+ tester ("test_cmd_line_parser_wchar_t",
+ "Runs tests on the cmd_line_parser<wchar_t> component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a with wchar_t";
+ cmd_line_parser_kernel_test<cmd_line_parser<wchar_t>::kernel_1a>();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_1a_c with wchar_t";
+ cmd_line_parser_kernel_test<cmd_line_parser<wchar_t>::kernel_1a_c>();
+ print_spinner();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/compress_stream.cpp b/ml/dlib/dlib/test/compress_stream.cpp
new file mode 100644
index 000000000..fbc57dd4c
--- /dev/null
+++ b/ml/dlib/dlib/test/compress_stream.cpp
@@ -0,0 +1,306 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <cstdlib>
+
+#include <dlib/compress_stream.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.compress_stream");
+
+ template <
+ typename cs
+ >
+ void compress_stream_kernel_test (
+ unsigned long seed
+ )
+ /*!
+ requires
+ - cs is an implementation of compress_stream/compress_stream_kernel_abstract.h
+ the alphabet_size for cc is 256
+ ensures
+ - runs tests on cs for compliance with the specs
+ !*/
+ {
+
+
+ srand(seed);
+
+ cs test;
+
+
+ dlog << LTRACE << 1;
+
+ int count = 0;
+ while (count < 2)
+ {
+ print_spinner();
+ istringstream sin;
+ ostringstream sout;
+ string buffer;
+ buffer.reserve(10000);
+ // fill sin with a bunch of random data in the range 0 to 63
+ for (int i = 0; i < 10000; ++i)
+ {
+ char temp = static_cast<char>(::rand()&0x3f);
+ buffer.push_back(temp);
+ }
+
+ print_spinner();
+ sin.str(buffer);
+ string old_buffer = buffer;
+
+ test.compress(sin,sout);
+ buffer = sout.str();
+
+ print_spinner();
+ // corrput the data in buffer
+ buffer[buffer.size()/2]++;
+
+ sin.str(buffer);
+ sout.str("");
+
+ bool detected_error = false;
+ try {
+ test.decompress(sin,sout);
+ } catch ( typename cs::decompression_error e )
+ {
+ detected_error = true;
+ ++count;
+ }
+
+
+ DLIB_TEST_MSG(detected_error || sout.str() == old_buffer,(unsigned int)sout.str().size());
+
+
+
+ } /**/
+
+
+ dlog << LTRACE << 2;
+
+ for (int j = 0; j < 2; ++j)
+ {
+
+ print_spinner();
+ istringstream sin;
+ ostringstream sout;
+
+ string buffer;
+
+ buffer.reserve(10);
+
+ // make sure a single char can be compressed and decompressed
+ for (int i = 0; i < 256; ++i)
+ {
+ sin.str("");
+ sout.str("");
+ char ch = static_cast<char>(i);
+ buffer = ch;
+ sin.str(buffer);
+
+ test.compress(sin,sout);
+
+ sin.str(sout.str());
+ sout.str("");
+ test.decompress(sin,sout);
+ DLIB_TEST(sout.str() == buffer);
+ }
+
+ print_spinner();
+
+ // make sure you can compress a single char, then append a new
+ // compressed single char. and make sure you can decode the
+ // two streams. Just to make sure the decoder doesn't leave
+ // extra bytes behind or eat more than it should.
+ for (int i = 0; i < 500; ++i)
+ {
+ sin.str("");
+ sin.clear();
+ sout.str("");
+ sout.clear();
+ char ch = static_cast<char>(::rand()%256);
+ char ch2 = static_cast<char>(::rand()%256);
+
+ buffer = ch;
+ sin.str(buffer);
+
+
+
+ test.compress(sin,sout);
+
+
+
+
+ buffer = ch2;
+ sin.str(buffer);
+ test.compress(sin,sout);
+
+ sin.str(sout.str());
+
+ sout.str("");
+ test.decompress(sin,sout);
+ buffer = ch;
+ DLIB_TEST(sout.str() == buffer);
+
+
+
+
+ sout.str("");
+ test.decompress(sin,sout);
+ buffer = ch2;
+ DLIB_TEST(sout.str() == buffer);
+
+
+ }
+ print_spinner();
+
+
+ // make sure you can compress and decompress the empty string
+ sout.str("");
+ sin.str("");
+ test.compress(sin,sout);
+ sin.str(sout.str());
+ sout.str("");
+ test.decompress(sin,sout);
+ DLIB_TEST_MSG(sout.str() == "",sout.str());
+
+
+
+
+
+ print_spinner();
+
+ sin.str("");
+ sout.str("");
+ buffer = "";
+
+ buffer.reserve(20000);
+ // fill buffer with a bunch of random data in the range 0 to 63
+ for (int i = 0; i < 20000; ++i)
+ {
+ char temp = static_cast<char>(::rand()&0x3f);
+ buffer.push_back(temp);
+ }
+
+ sin.str(buffer);
+
+ print_spinner();
+ test.compress(sin,sout);
+
+ sin.str(sout.str());
+ sout.str("");
+
+ print_spinner();
+ test.decompress(sin,sout);
+
+ DLIB_TEST(sout.str() == buffer);
+
+ print_spinner();
+ }
+
+ dlog << LTRACE << 3;
+
+ // this block will try to compress a bunch of 'a' chars
+ {
+
+ istringstream sin;
+ ostringstream sout;
+
+ string buffer;
+
+
+ print_spinner();
+
+ sin.str("");
+ sout.str("");
+ buffer = "";
+
+ buffer.reserve(50000);
+ // fill buffer with a bunch of 'a' chars
+ for (int i = 0; i < 50000; ++i)
+ {
+ char temp = 'a';
+ buffer.push_back(temp);
+ }
+
+ sin.str(buffer);
+
+ print_spinner();
+ test.compress(sin,sout);
+
+ sin.str(sout.str());
+ sout.str("");
+
+ print_spinner();
+ test.decompress(sin,sout);
+
+ DLIB_TEST(sout.str() == buffer);
+
+ print_spinner();
+
+ }
+
+ dlog << LTRACE << 4;
+
+ }
+
+
+
+
+
+
+ class compress_stream_tester : public tester
+ {
+ public:
+ compress_stream_tester (
+ ) :
+ tester ("test_compress_stream",
+ "Runs tests on the compress_stream component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ const unsigned int seed = static_cast<unsigned int>(time(0));
+ dlog << LINFO << "using seed: " << seed;
+
+ dlog << LINFO << "testing kernel_1a";
+ compress_stream_kernel_test<compress_stream::kernel_1a>(seed);
+ dlog << LINFO << "testing kernel_1b";
+ compress_stream_kernel_test<compress_stream::kernel_1b>(seed);
+ dlog << LINFO << "testing kernel_1c";
+ compress_stream_kernel_test<compress_stream::kernel_1c>(seed);
+ dlog << LINFO << "testing kernel_1da";
+ compress_stream_kernel_test<compress_stream::kernel_1da>(seed);
+ dlog << LINFO << "testing kernel_1db";
+ compress_stream_kernel_test<compress_stream::kernel_1db>(seed);
+ dlog << LINFO << "testing kernel_1ea";
+ compress_stream_kernel_test<compress_stream::kernel_1ea>(seed);
+ dlog << LINFO << "testing kernel_1eb";
+ compress_stream_kernel_test<compress_stream::kernel_1eb>(seed);
+ dlog << LINFO << "testing kernel_1ec";
+ compress_stream_kernel_test<compress_stream::kernel_1ec>(seed);
+ dlog << LINFO << "testing kernel_2a";
+ compress_stream_kernel_test<compress_stream::kernel_2a>(seed);
+ dlog << LINFO << "testing kernel_3a";
+ compress_stream_kernel_test<compress_stream::kernel_3a>(seed);
+ dlog << LINFO << "testing kernel_3b";
+ compress_stream_kernel_test<compress_stream::kernel_3b>(seed);
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/conditioning_class.cpp b/ml/dlib/dlib/test/conditioning_class.cpp
new file mode 100644
index 000000000..b4415eafd
--- /dev/null
+++ b/ml/dlib/dlib/test/conditioning_class.cpp
@@ -0,0 +1,86 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <cstdlib>
+
+#include <dlib/conditioning_class.h>
+
+#include "tester.h"
+#include "conditioning_class.h"
+
+namespace
+{
+
+
+ class conditioning_class_tester : public tester
+ {
+ public:
+ conditioning_class_tester (
+ ) :
+ tester ("test_conditioning_class",
+ "Runs tests on the conditioning_class component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_1a,
+ conditioning_class<2>::kernel_1a
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_2a";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_2a,
+ conditioning_class<2>::kernel_2a
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_3a";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_3a,
+ conditioning_class<2>::kernel_3a
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_4a";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_4a,
+ conditioning_class<2>::kernel_4a
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_4b";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_4b,
+ conditioning_class<2>::kernel_4b
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_4c";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_4c,
+ conditioning_class<2>::kernel_4c
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_4d";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_4d,
+ conditioning_class<2>::kernel_4d
+ >();
+ print_spinner();
+
+
+ }
+ } a;
+
+
+}
+
diff --git a/ml/dlib/dlib/test/conditioning_class.h b/ml/dlib/dlib/test/conditioning_class.h
new file mode 100644
index 000000000..3c6c88b8d
--- /dev/null
+++ b/ml/dlib/dlib/test/conditioning_class.h
@@ -0,0 +1,841 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_TEST_CONDITIONING_CLASs_H_
+#define DLIB_TEST_CONDITIONING_CLASs_H_
+
+
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <cstdlib>
+
+#include <dlib/conditioning_class.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.conditioning_class");
+
+ template <
+ typename cc,
+ typename cc2
+ >
+ void conditioning_class_kernel_test (
+ )
+ /*!
+ requires
+ - cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
+ the alphabet_size for cc is 256
+ - cc2 is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
+ the alphabet_size for cc2 is 2
+ ensures
+ - runs tests on cc for compliance with the specs
+ !*/
+ {
+
+ srand(static_cast<unsigned int>(time(0)));
+
+
+
+ typename cc::global_state_type gs;
+ typename cc2::global_state_type gs2;
+
+
+
+
+ for (int g = 0; g < 2; ++g)
+ {
+ print_spinner();
+ unsigned long amount=g+1;
+ cc2 test(gs2);
+ cc2 test2(gs2);
+
+
+ DLIB_TEST(test.get_memory_usage() != 0);
+
+ const unsigned long alphabet_size = 2;
+
+
+ DLIB_TEST(test.get_total() == 1);
+
+ DLIB_TEST(test.get_count(alphabet_size-1)==1);
+ for (unsigned long i = 0; i < alphabet_size-1; ++i)
+ {
+ unsigned long low_count, high_count, total_count;
+ DLIB_TEST_MSG(test.get_range(i,low_count,high_count,total_count) == 0,i);
+ DLIB_TEST(test.get_count(i) == 0);
+ DLIB_TEST(test.get_total() == 1);
+ }
+
+
+
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ test.increment_count(i,static_cast<unsigned short>(amount));
+ unsigned long low_count = 0, high_count = 0, total_count = 0;
+
+ if (i ==alphabet_size-1)
+ {
+ DLIB_TEST(test.get_range(i,low_count,high_count,total_count) == 1+amount);
+
+ DLIB_TEST(high_count == low_count+1+amount);
+ DLIB_TEST(total_count == test.get_total());
+
+
+ DLIB_TEST(test.get_count(i) == 1+amount);
+ }
+ else
+ {
+ DLIB_TEST(test.get_range(i,low_count,high_count,total_count) == amount);
+
+ DLIB_TEST(high_count == low_count+amount);
+ DLIB_TEST(total_count == test.get_total());
+
+
+ DLIB_TEST(test.get_count(i) == amount);
+ }
+ DLIB_TEST(test.get_total() == (i+1)*amount + 1);
+ }
+
+
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ unsigned long temp = static_cast<unsigned long>(::rand()%40);
+ for (unsigned long j = 0; j < temp; ++j)
+ {
+ test.increment_count(i,static_cast<unsigned short>(amount));
+ if (i == alphabet_size-1)
+ {
+ DLIB_TEST(test.get_count(i) == (j+1)*amount + 1 + amount);
+ }
+ else
+ {
+ DLIB_TEST(test.get_count(i) == (j+1)*amount + amount);
+ }
+ }
+
+ unsigned long target = test.get_total()/2;
+ unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0;
+
+ if (i == alphabet_size-1)
+ {
+ DLIB_TEST(test.get_range(symbol,low_count,high_count,total_count)==temp*amount+1+amount);
+ DLIB_TEST(high_count-low_count == temp*amount+1+amount);
+ }
+ else
+ {
+ DLIB_TEST(test.get_range(symbol,low_count,high_count,total_count)==temp*amount + amount);
+ DLIB_TEST(high_count-low_count == temp*amount + amount);
+ }
+ DLIB_TEST(total_count == test.get_total());
+
+ test.get_symbol(target,symbol,low_count,high_count);
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ DLIB_TEST(low_count <= target);
+ DLIB_TEST(target < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+
+ }
+
+ test.clear();
+
+
+ for (unsigned long i = 0; i < alphabet_size-1; ++i)
+ {
+ test.increment_count(i);
+ unsigned long low_count = 0, high_count = 0, total_count = 0;
+ DLIB_TEST(test.get_range(i,low_count,high_count,total_count) == 1);
+
+ DLIB_TEST(high_count == low_count+1);
+ DLIB_TEST(total_count == test.get_total());
+
+ DLIB_TEST(test.get_count(i) == 1);
+ DLIB_TEST(test.get_total() == i+2);
+ }
+
+
+
+
+ unsigned long counts[alphabet_size];
+
+
+ print_spinner();
+ for (int k = 0; k < 10; ++k)
+ {
+ unsigned long range = ::rand()%50000 + 2;
+
+ test.clear();
+
+ for (unsigned long i = 0; i < alphabet_size-1; ++i)
+ counts[i] = 0;
+ unsigned long total = 1;
+ counts[alphabet_size-1] = 1;
+
+
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ unsigned long temp = static_cast<unsigned long>(::rand()%range);
+ for (unsigned long j = 0; j < temp; ++j)
+ {
+ test.increment_count(i);
+
+
+ if (total >= 65535)
+ {
+ total = 0;
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ counts[i] >>= 1;
+ total += counts[i];
+ }
+ if (counts[alphabet_size-1]==0)
+ {
+ counts[alphabet_size-1] = 1;
+ ++total;
+ }
+ }
+ counts[i] = counts[i] + 1;
+ ++total;
+
+
+ }
+
+
+ unsigned long temp_total = 0;
+ for (unsigned long a = 0; a < alphabet_size; ++a)
+ {
+ temp_total += test.get_count(a);
+ }
+ DLIB_TEST_MSG(temp_total == test.get_total(),
+ "temp_total == " << temp_total << endl <<
+ "test.get_total() == " << test.get_total()
+ );
+
+ DLIB_TEST(test.get_count(alphabet_size-1) == counts[alphabet_size-1]);
+ DLIB_TEST_MSG(test.get_total() == total,
+ "test.get_total() == " << test.get_total() << endl <<
+ "total == " << total
+ );
+
+ unsigned long target = test.get_total()/2;
+ unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0;
+
+
+ DLIB_TEST(test.get_range(symbol,low_count,high_count,total_count)==counts[symbol]);
+
+ if (counts[symbol] != 0)
+ {
+ DLIB_TEST(total_count == total);
+
+ DLIB_TEST(high_count <= total);
+ DLIB_TEST(low_count < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ }
+
+
+ if (target < total)
+ {
+ test.get_symbol(target,symbol,low_count,high_count);
+
+
+ DLIB_TEST(high_count <= total);
+ DLIB_TEST(low_count < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ DLIB_TEST(test.get_count(symbol) == counts[symbol]);
+ }
+
+
+
+
+ }
+
+ }
+
+ print_spinner();
+
+ for (unsigned long h = 0; h < 10; ++h)
+ {
+ test.clear();
+ DLIB_TEST(test.get_total() == 1);
+
+ // fill out test with some numbers
+ unsigned long temp = ::rand()%30000 + 50000;
+ for (unsigned long j = 0; j < temp; ++j)
+ {
+ unsigned long symbol = (unsigned long)::rand()%alphabet_size;
+ test.increment_count(symbol);
+ }
+
+ // make sure all symbols have a count of at least one
+ for (unsigned long j = 0; j < alphabet_size; ++j)
+ {
+ if (test.get_count(j) == 0)
+ test.increment_count(j);
+ }
+
+ unsigned long temp_total = 0;
+ for (unsigned long j = 0; j < alphabet_size; ++j)
+ {
+ temp_total += test.get_count(j);
+ }
+ DLIB_TEST(temp_total == test.get_total());
+
+
+ unsigned long low_counts[alphabet_size];
+ unsigned long high_counts[alphabet_size];
+ // iterate over all the symbols
+ for (unsigned long j = 0; j < alphabet_size; ++j)
+ {
+ unsigned long total;
+ unsigned long count = test.get_range(j,low_counts[j],high_counts[j],total);
+ DLIB_TEST(count == test.get_count(j));
+ DLIB_TEST(count == high_counts[j] - low_counts[j]);
+
+ }
+
+
+ // make sure get_symbol() matches what get_range() told us
+ for (unsigned long j = 0; j < alphabet_size; ++j)
+ {
+ for (unsigned long k = low_counts[j]; k < high_counts[j]; ++k)
+ {
+ unsigned long symbol, low_count, high_count;
+ test.get_symbol(k,symbol,low_count,high_count);
+ DLIB_TEST(high_count - low_count == test.get_count(symbol));
+ DLIB_TEST_MSG(j == symbol,
+ "j == " << j << endl <<
+ "k == " << k << endl <<
+ "symbol == " << symbol << endl <<
+ "low_counts[j] == " << low_counts[j] << endl <<
+ "high_counts[j] == " << high_counts[j] << endl <<
+ "low_counts[symbol] == " << low_counts[symbol] << endl <<
+ "high_counts[symbol] == " << high_counts[symbol] << endl <<
+ "low_count == " << low_count << endl <<
+ "high_count == " << high_count << endl <<
+ "temp.count(j) == " << test.get_count(j)
+ );
+ DLIB_TEST_MSG(low_count == low_counts[j],
+ "symbol: " << j << "\n" <<
+ "target: " << k << "\n" <<
+ "low_count: " << low_count << "\n" <<
+ "low_counts[j]: " << low_counts[j]);
+ DLIB_TEST(high_count == high_counts[j]);
+ }
+
+ }
+
+ }
+
+
+
+ print_spinner();
+
+ for (int h = 0; h < 10; ++h)
+ {
+
+
+ test.clear();
+
+ for (unsigned long k = 0; k < alphabet_size-1; ++k)
+ {
+ counts[k] = 0;
+ }
+ counts[alphabet_size-1] = 1;
+ unsigned long total = 1;
+ unsigned long i = ::rand()%alphabet_size;
+
+ unsigned long temp = 65536;
+ for (unsigned long j = 0; j < temp; ++j)
+ {
+ test.increment_count(i);
+
+
+ if (total >= 65535)
+ {
+ total = 0;
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ counts[i] >>= 1;
+ total += counts[i];
+ }
+ if (counts[alphabet_size-1] == 0)
+ {
+ ++total;
+ counts[alphabet_size-1] = 1;
+ }
+ }
+ counts[i] = counts[i] + 1;
+ ++total;
+
+ }
+
+
+ DLIB_TEST(test.get_total() == total);
+
+ unsigned long target = test.get_total()/2;
+ unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0;
+
+
+ DLIB_TEST(test.get_range(symbol,low_count,high_count,total_count)==counts[symbol]);
+
+ if (counts[symbol] != 0)
+ {
+ DLIB_TEST(total_count == total);
+
+ DLIB_TEST(high_count <= total);
+ DLIB_TEST(low_count < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ }
+
+
+
+ test.get_symbol(target,symbol,low_count,high_count);
+
+
+ DLIB_TEST(high_count <= total);
+ DLIB_TEST(low_count < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ DLIB_TEST(test.get_count(symbol) == counts[symbol]);
+
+
+
+
+
+
+
+ }
+
+ } // for (int g = 0; g < 2; ++g)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ for (int g = 0; g < 2; ++g)
+ {
+ print_spinner();
+ unsigned long amount=g+1;
+ cc test(gs);
+ cc test2(gs);
+
+ DLIB_TEST(test.get_memory_usage() != 0);
+
+ const unsigned long alphabet_size = 256;
+
+
+ DLIB_TEST(test.get_total() == 1);
+
+ DLIB_TEST(test.get_count(alphabet_size-1)==1);
+ for (unsigned long i = 0; i < alphabet_size-1; ++i)
+ {
+ unsigned long low_count, high_count, total_count;
+ DLIB_TEST(test.get_range(i,low_count,high_count,total_count) == 0);
+ DLIB_TEST(test.get_count(i) == 0);
+ DLIB_TEST(test.get_total() == 1);
+ }
+
+
+ bool oom = false;
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ bool status = test.increment_count(i,static_cast<unsigned short>(amount));
+ unsigned long low_count = 0, high_count = 0, total_count = 0;
+ if (!status)
+ oom = true;
+
+ if (status)
+ {
+ if (i ==alphabet_size-1)
+ {
+ DLIB_TEST(test.get_range(i,low_count,high_count,total_count) == 1+amount);
+
+ DLIB_TEST(high_count == low_count+1+amount);
+ DLIB_TEST(total_count == test.get_total());
+
+
+ DLIB_TEST(test.get_count(i) == 1+amount);
+ }
+ else
+ {
+ DLIB_TEST(test.get_range(i,low_count,high_count,total_count) == amount);
+
+ DLIB_TEST(high_count == low_count+amount);
+ DLIB_TEST(total_count == test.get_total());
+
+
+ DLIB_TEST(test.get_count(i) == amount);
+ }
+ if (!oom)
+ DLIB_TEST(test.get_total() == (i+1)*amount + 1);
+ }
+ }
+
+
+ oom = false;
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ unsigned long temp = static_cast<unsigned long>(::rand()%40);
+ for (unsigned long j = 0; j < temp; ++j)
+ {
+ bool status = test.increment_count(i,static_cast<unsigned short>(amount));
+ if (!status)
+ oom = true;
+ if (status)
+ {
+ if (i == alphabet_size-1)
+ {
+ DLIB_TEST(test.get_count(i) == (j+1)*amount + 1 + amount);
+ }
+ else
+ {
+ DLIB_TEST(test.get_count(i) == (j+1)*amount + amount);
+ }
+ }
+ }
+
+ unsigned long target = test.get_total()/2;
+ unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0;
+
+ if (!oom)
+ {
+ if (i == alphabet_size-1)
+ {
+ DLIB_TEST(test.get_range(symbol,low_count,high_count,total_count)==temp*amount+1+amount);
+ DLIB_TEST(high_count-low_count == temp*amount+1+amount);
+ }
+ else
+ {
+ DLIB_TEST(test.get_range(symbol,low_count,high_count,total_count)==temp*amount + amount);
+ DLIB_TEST(high_count-low_count == temp*amount + amount);
+ }
+ DLIB_TEST(total_count == test.get_total());
+
+
+ test.get_symbol(target,symbol,low_count,high_count);
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ DLIB_TEST(low_count <= target);
+ DLIB_TEST(target < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ }
+
+ }
+
+ test.clear();
+
+
+ oom = false;
+ for (unsigned long i = 0; i < alphabet_size-1; ++i)
+ {
+ if(!test.increment_count(i))
+ oom = true;
+ unsigned long low_count = 0, high_count = 0, total_count = 0;
+
+ if (!oom)
+ {
+ DLIB_TEST(test.get_range(i,low_count,high_count,total_count) == 1);
+
+ DLIB_TEST(high_count == low_count+1);
+ DLIB_TEST(total_count == test.get_total());
+
+ DLIB_TEST(test.get_count(i) == 1);
+ DLIB_TEST(test.get_total() == i+2);
+ }
+ }
+
+
+
+ unsigned long counts[alphabet_size];
+
+
+ for (int k = 0; k < 10; ++k)
+ {
+ unsigned long range = ::rand()%50000 + 2;
+
+ test.clear();
+
+ for (unsigned long i = 0; i < alphabet_size-1; ++i)
+ counts[i] = 0;
+ unsigned long total = 1;
+ counts[alphabet_size-1] = 1;
+
+
+ oom = false;
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ unsigned long temp = static_cast<unsigned long>(::rand()%range);
+ for (unsigned long j = 0; j < temp; ++j)
+ {
+ if (!test.increment_count(i))
+ oom = true;
+
+
+ if (total >= 65535)
+ {
+
+ total = 0;
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ counts[i] >>= 1;
+ total += counts[i];
+ }
+ if (counts[alphabet_size-1]==0)
+ {
+ counts[alphabet_size-1] = 1;
+ ++total;
+ }
+ }
+ counts[i] = counts[i] + 1;
+ ++total;
+
+
+ }
+
+
+ unsigned long temp_total = 0;
+ for (unsigned long a = 0; a < alphabet_size; ++a)
+ {
+ temp_total += test.get_count(a);
+ }
+
+ if (!oom)
+ {
+ DLIB_TEST_MSG(temp_total == test.get_total(),
+ "temp_total == " << temp_total << endl <<
+ "test.get_total() == " << test.get_total()
+ );
+
+ DLIB_TEST(test.get_count(alphabet_size-1) == counts[alphabet_size-1]);
+ DLIB_TEST_MSG(test.get_total() == total,
+ "test.get_total() == " << test.get_total() << endl <<
+ "total == " << total
+ );
+ }
+
+ unsigned long target = test.get_total()/2;
+ unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0;
+
+ if (!oom)
+ {
+
+ DLIB_TEST(test.get_range(symbol,low_count,high_count,total_count)==counts[symbol]);
+
+ if (counts[symbol] != 0)
+ {
+ DLIB_TEST(total_count == total);
+
+ DLIB_TEST(high_count <= total);
+ DLIB_TEST(low_count < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ }
+
+
+ if (target < total)
+ {
+ test.get_symbol(target,symbol,low_count,high_count);
+
+
+ DLIB_TEST(high_count <= total);
+ DLIB_TEST(low_count < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ DLIB_TEST(test.get_count(symbol) == counts[symbol]);
+ }
+ }
+
+
+
+ }
+
+ }
+
+ oom = false;
+ for (unsigned long h = 0; h < 10; ++h)
+ {
+ test.clear();
+ DLIB_TEST(test.get_total() == 1);
+
+ // fill out test with some numbers
+ unsigned long temp = ::rand()%30000 + 50000;
+ for (unsigned long j = 0; j < temp; ++j)
+ {
+ unsigned long symbol = (unsigned long)::rand()%alphabet_size;
+ if (!test.increment_count(symbol))
+ oom = true;
+ }
+
+ // make sure all symbols have a count of at least one
+ for (unsigned long j = 0; j < alphabet_size; ++j)
+ {
+ if (test.get_count(j) == 0)
+ test.increment_count(j);
+ }
+
+ unsigned long temp_total = 0;
+ for (unsigned long j = 0; j < alphabet_size; ++j)
+ {
+ temp_total += test.get_count(j);
+ }
+ if (!oom)
+ DLIB_TEST(temp_total == test.get_total());
+
+
+ unsigned long low_counts[alphabet_size];
+ unsigned long high_counts[alphabet_size];
+
+ if (!oom)
+ {
+
+ // iterate over all the symbols
+ for (unsigned long j = 0; j < alphabet_size; ++j)
+ {
+ unsigned long total;
+ unsigned long count = test.get_range(j,low_counts[j],high_counts[j],total);
+ DLIB_TEST(count == test.get_count(j));
+ DLIB_TEST(count == high_counts[j] - low_counts[j]);
+
+ }
+
+
+
+
+ // make sure get_symbol() matches what get_range() told us
+ for (unsigned long j = 0; j < alphabet_size; ++j)
+ {
+ for (unsigned long k = low_counts[j]; k < high_counts[j]; ++k)
+ {
+ unsigned long symbol, low_count, high_count;
+ test.get_symbol(k,symbol,low_count,high_count);
+ DLIB_TEST(high_count - low_count == test.get_count(symbol));
+ DLIB_TEST_MSG(j == symbol,
+ "j == " << j << endl <<
+ "k == " << k << endl <<
+ "symbol == " << symbol << endl <<
+ "low_counts[j] == " << low_counts[j] << endl <<
+ "high_counts[j] == " << high_counts[j] << endl <<
+ "low_counts[symbol] == " << low_counts[symbol] << endl <<
+ "high_counts[symbol] == " << high_counts[symbol] << endl <<
+ "low_count == " << low_count << endl <<
+ "high_count == " << high_count << endl <<
+ "temp.count(j) == " << test.get_count(j)
+ );
+ DLIB_TEST_MSG(low_count == low_counts[j],
+ "symbol: " << j << "\n" <<
+ "target: " << k << "\n" <<
+ "low_count: " << low_count << "\n" <<
+ "low_counts[j]: " << low_counts[j]);
+ DLIB_TEST(high_count == high_counts[j]);
+ }
+
+ }
+ }
+
+ }
+
+
+
+
+ for (int h = 0; h < 10; ++h)
+ {
+
+
+ test.clear();
+
+ for (unsigned long k = 0; k < alphabet_size-1; ++k)
+ {
+ counts[k] = 0;
+ }
+ counts[alphabet_size-1] = 1;
+ unsigned long total = 1;
+ unsigned long i = ::rand()%alphabet_size;
+
+ unsigned long temp = 65536;
+ for (unsigned long j = 0; j < temp; ++j)
+ {
+ test.increment_count(i);
+
+
+ if (total >= 65535)
+ {
+ total = 0;
+ for (unsigned long i = 0; i < alphabet_size; ++i)
+ {
+ counts[i] >>= 1;
+ total += counts[i];
+ }
+ if (counts[alphabet_size-1] == 0)
+ {
+ ++total;
+ counts[alphabet_size-1] = 1;
+ }
+ }
+ counts[i] = counts[i] + 1;
+ ++total;
+
+ }
+
+
+ DLIB_TEST(test.get_total() == total);
+
+ unsigned long target = test.get_total()/2;
+ unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0;
+
+
+ DLIB_TEST(test.get_range(symbol,low_count,high_count,total_count)==counts[symbol]);
+
+ if (counts[symbol] != 0)
+ {
+ DLIB_TEST(total_count == total);
+
+ DLIB_TEST(high_count <= total);
+ DLIB_TEST(low_count < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ }
+
+
+
+ test.get_symbol(target,symbol,low_count,high_count);
+
+
+ DLIB_TEST(high_count <= total);
+ DLIB_TEST(low_count < high_count);
+ DLIB_TEST(high_count <= test.get_total());
+ DLIB_TEST(test.get_count(symbol) == high_count-low_count);
+ DLIB_TEST(test.get_count(symbol) == counts[symbol]);
+
+
+
+
+
+
+
+ }
+
+ } // for (int g = 0; g < 2; ++g)
+
+
+ }
+
+}
+
+#endif // DLIB_TEST_CONDITIONING_CLASs_H_
+
diff --git a/ml/dlib/dlib/test/conditioning_class_c.cpp b/ml/dlib/dlib/test/conditioning_class_c.cpp
new file mode 100644
index 000000000..4bfd9f32a
--- /dev/null
+++ b/ml/dlib/dlib/test/conditioning_class_c.cpp
@@ -0,0 +1,87 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <cstdlib>
+
+#include <dlib/conditioning_class.h>
+
+#include "tester.h"
+#include "conditioning_class.h"
+
+namespace
+{
+
+
+ class conditioning_class_tester : public tester
+ {
+ public:
+ conditioning_class_tester (
+ ) :
+ tester ("test_conditioning_class_c",
+ "Runs tests on the conditioning_class checked components.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a_c";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_1a_c,
+ conditioning_class<2>::kernel_1a_c
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_2a_c";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_2a_c,
+ conditioning_class<2>::kernel_2a_c
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_3a_c";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_3a_c,
+ conditioning_class<2>::kernel_3a_c
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_4a_c";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_4a_c,
+ conditioning_class<2>::kernel_4a_c
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_4b_c";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_4b_c,
+ conditioning_class<2>::kernel_4b_c
+ >();
+ print_spinner();
+
+
+ dlog << LINFO << "testing kernel_4c_c";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_4c_c,
+ conditioning_class<2>::kernel_4c_c
+ >();
+ print_spinner();
+
+ dlog << LINFO << "testing kernel_4d_c";
+ conditioning_class_kernel_test<
+ conditioning_class<256>::kernel_4d_c,
+ conditioning_class<2>::kernel_4d_c
+ >();
+ print_spinner();
+
+
+ }
+ } a;
+
+
+}
+
diff --git a/ml/dlib/dlib/test/config_reader.cpp b/ml/dlib/dlib/test/config_reader.cpp
new file mode 100644
index 000000000..20b5215f3
--- /dev/null
+++ b/ml/dlib/dlib/test/config_reader.cpp
@@ -0,0 +1,509 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/config_reader.h>
+#include <dlib/cmd_line_parser.h>
+
+#include "tester.h"
+
+// This is called an unnamed-namespace and it has the effect of making everything inside this file "private"
+// so that everything you declare will have static linkage. Thus we won't have any multiply
+// defined symbol errors coming out of the linker when we try to compile the test suite.
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ // Declare the logger we will use in this test. The name of the tester
+ // should start with "test."
+ logger dlog("test.config_reader");
+
+ template <
+ typename config_reader
+ >
+ void do_the_tests (
+ config_reader& cr
+ )
+ {
+ DLIB_TEST(cr.is_key_defined("global"));
+ DLIB_TEST(cr.is_block_defined("all"));
+ DLIB_TEST(cr.is_key_defined("globalasfd") == false);
+ DLIB_TEST(cr.is_block_defined("all!") == false);
+ DLIB_TEST(cr["global"] == "hmm");
+ DLIB_TEST(cr["global2"] == "hmm2");
+
+ std_vector_c<string> blocks;
+ cr.block("all").get_blocks(blocks);
+ DLIB_TEST(blocks.size() == 4);
+ cr.block("all").block("block1").get_blocks(blocks); DLIB_TEST(blocks.size() == 0);
+ cr.block("all").block("block2").get_blocks(blocks); DLIB_TEST(blocks.size() == 0);
+ cr.block("all").block("block3").get_blocks(blocks); DLIB_TEST(blocks.size() == 0);
+ cr.block("all").block("block4").get_blocks(blocks); DLIB_TEST(blocks.size() == 0);
+
+ DLIB_TEST(cr.block("all").block("block1").is_key_defined("name"));
+ DLIB_TEST(cr.block("all").block("block2").is_key_defined("name"));
+ DLIB_TEST(cr.block("all").block("block3").is_key_defined("name"));
+ DLIB_TEST(cr.block("all").block("block4").is_key_defined("name"));
+ DLIB_TEST(cr.block("all").block("block1").is_key_defined("age"));
+ DLIB_TEST(cr.block("all").block("block2").is_key_defined("age"));
+ DLIB_TEST(cr.block("all").block("block3").is_key_defined("age"));
+ DLIB_TEST(cr.block("all").block("block4").is_key_defined("age"));
+
+ DLIB_TEST(cr.block("all").block("block1")["name"] == "davis king");
+ DLIB_TEST(cr.block("all").block("block2")["name"] == "joel");
+ DLIB_TEST(cr.block("all").block("block3")["name"] == "john");
+ DLIB_TEST(cr.block("all").block("block4")["name"] == "dude");
+ DLIB_TEST(cr.block("all").block("block1")["age"] == "24");
+ DLIB_TEST(cr.block("all").block("block2")["age"] == "24");
+ DLIB_TEST(cr.block("all").block("block3")["age"] == "24");
+ DLIB_TEST(cr.block("all").block("block4")["age"] == "53");
+
+
+ int count2 = 0;
+ cr.get_blocks(blocks);
+ DLIB_TEST(blocks.size() == 1);
+ DLIB_TEST(blocks[0] == "all");
+
+
+ DLIB_TEST(cr.block("all").is_key_defined("global") == false);
+ DLIB_TEST(cr.block("all").is_key_defined("global2") == false);
+ DLIB_TEST(cr.block("all").is_key_defined("name") == false);
+ DLIB_TEST(cr.block("all").is_key_defined("age") == false);
+
+ cr.block("all").get_blocks(blocks);
+ DLIB_TEST(blocks.size() == 4);
+ std::vector<string> temp_blocks;
+ for (unsigned long i = 0; i < blocks.size(); ++i)
+ {
+ ++count2;
+ ostringstream sout;
+ sout << "block" << count2;
+ DLIB_TEST(blocks[i] == sout.str());
+
+ cr.block("all").block(blocks[i]).get_blocks(temp_blocks);
+ DLIB_TEST(temp_blocks.size() == 0);
+
+ DLIB_TEST(cr.block("all").block(blocks[i]).is_key_defined("name"));
+ DLIB_TEST(cr.block("all").block(blocks[i]).is_key_defined("age"));
+ }
+
+
+
+ bool found_error = false;
+ try
+ {
+ cr.block("bogus_block");
+ }
+ catch (typename config_reader::config_reader_access_error& e)
+ {
+ DLIB_TEST(e.block_name == "bogus_block");
+ DLIB_TEST(e.key_name == "");
+ found_error = true;
+ }
+ DLIB_TEST(found_error);
+
+ found_error = false;
+ try
+ {
+ cr["bogus_key"];
+ }
+ catch (typename config_reader::config_reader_access_error& e)
+ {
+ DLIB_TEST(e.block_name == "");
+ DLIB_TEST(e.key_name == "bogus_key");
+ found_error = true;
+ }
+ DLIB_TEST(found_error);
+
+
+ found_error = false;
+ try
+ {
+ cr.block("all").block("block10");
+ }
+ catch (typename config_reader::config_reader_access_error& e)
+ {
+ DLIB_TEST(e.block_name == "block10");
+ DLIB_TEST(e.key_name == "");
+ found_error = true;
+ }
+ DLIB_TEST(found_error);
+
+ found_error = false;
+ try
+ {
+ cr.block("all")["msdofg"];
+ }
+ catch (typename config_reader::config_reader_access_error& e)
+ {
+ DLIB_TEST(e.block_name == "");
+ DLIB_TEST(e.key_name == "msdofg");
+ found_error = true;
+ }
+ DLIB_TEST(found_error);
+
+ }
+
+
+
+ template <
+ typename config_reader
+ >
+ void config_reader_test (
+ )
+ /*!
+ requires
+ - config_reader is an implementation of config_reader/config_reader_kernel_abstract.h
+ is instantiated with int
+ ensures
+ - runs tests on config_reader for compliance with the specs
+ !*/
+ {
+
+
+
+ ostringstream sout;
+
+ sout << "all#comment { { } \n";
+ sout << "{ \n";
+ sout << " block1 \n";
+ sout << " { \n";
+ sout << " name = davis king \n";
+ sout << " age = 24 \n";
+ sout << " } \n";
+ sout << " \n";
+ sout << " block2 \n";
+ sout << " { \n";
+ sout << " name= joel \n";
+ sout << " age =24 \n";
+ sout << " } \n";
+ sout << " \n";
+ sout << " block3 \n";
+ sout << " { \n";
+ sout << " name = john \n";
+ sout << " age = 24 \n";
+ sout << " } \n";
+ sout << " #comment \n";
+ sout << "#comment \n";
+ sout << " block4{ # comment";
+ sout << " \n";
+ sout << " name = dude \n";
+ sout << " age = 53}\n";
+ sout << " \n";
+ sout << "} \n";
+ sout << " \n";
+ sout << " \n";
+ sout << "global=hmm#comment \n";
+ sout << "global2=hmm2 \n";
+ sout << " # comment \n";
+
+ string data = sout.str();
+
+ config_reader cr2;
+ for (int i = 0; i < 3; ++i)
+ {
+ istringstream sin;
+
+ sin.clear();
+ sin.str(data);
+
+ config_reader cr(sin);
+ sin.clear();
+ sin.str(data);
+
+ cr2.load_from(sin);
+
+ do_the_tests(cr);
+ do_the_tests(cr2);
+
+ cr.clear();
+ DLIB_TEST(cr.is_key_defined("global") == false);
+ }
+
+
+ sout.clear();
+ sout.str("");
+
+ {
+ sout << "all#comment { { } \n";
+ sout << "{ \n";
+ sout << " block1 \n";
+ sout << " { \n";
+ sout << " name = davis king \n";
+ sout << " age = 24 \n";
+ sout << " } \n";
+ sout << " \n";
+ sout << " block2 \n";
+ sout << " { \n";
+ sout << " name= joel \n";
+ sout << " age =24 \n";
+ sout << " } \n";
+ sout << " \n";
+ sout << " block3 \n";
+ sout << " {{ \n"; // error on this line
+ sout << " name = john \n";
+ sout << " age = 24 \n";
+ sout << " } \n";
+ sout << " #comment \n";
+ sout << "#comment \n";
+ sout << " block4{ # comment";
+ sout << " \n";
+ sout << " name = dude \n";
+ sout << " age = 53}\n";
+ sout << " \n";
+ sout << "} \n";
+ sout << " \n";
+ sout << " \n";
+ sout << "global=hmm#comment \n";
+ sout << "global2=hmm2 \n";
+ sout << " # comment \n";
+
+ istringstream sin(sout.str());
+
+ bool error_found = false;
+ try
+ {
+ cr2.load_from(sin);
+ }
+ catch (typename config_reader::config_reader_error& e)
+ {
+ error_found = true;
+ DLIB_TEST(e.line_number == 16);
+ DLIB_TEST(e.redefinition == false);
+ }
+ DLIB_TEST(error_found);
+ }
+
+ {
+ sout.str("");
+ sout.clear();
+ sout << "all#comment { { } \n";
+ sout << "{ \n";
+ sout << " block1 \n";
+ sout << " { \n";
+ sout << " name = davis king \n";
+ sout << " age = 24 \n";
+ sout << " } \n";
+ sout << " \n";
+ sout << " block2 \n";
+ sout << " { \n";
+ sout << " name= joel \n";
+ sout << " age =24 \n";
+ sout << " } \n";
+ sout << " \n";
+ sout << " block3 \n";
+ sout << " { \n";
+ sout << " name = john \n";
+ sout << " age = 24 \n";
+ sout << " } \n";
+ sout << " #comment \n";
+ sout << "#comment \n";
+ sout << " block4{ # comment";
+ sout << " \n";
+ sout << " name = dude \n";
+ sout << " age = 53}\n";
+ sout << " \n";
+ sout << "} \n";
+ sout << " \n";
+ sout << " \n";
+ sout << "global=hmm#comment \n";
+ sout << " \n";
+ sout << "global=hmm2 \n"; // error on this line
+ sout << " # comment \n";
+
+ istringstream sin(sout.str());
+
+ bool error_found = false;
+ try
+ {
+ cr2.load_from(sin);
+ }
+ catch (typename config_reader::config_reader_error& e)
+ {
+ error_found = true;
+ DLIB_TEST_MSG(e.line_number == 31,e.line_number);
+ DLIB_TEST(e.redefinition == true);
+ }
+ DLIB_TEST(error_found);
+ }
+
+
+ {
+ sout.str("");
+ sout.clear();
+ sout << "all#comment { { } \n";
+ sout << "{ \n";
+ sout << " block1 \n";
+ sout << " { \n";
+ sout << " name = davis king \n";
+ sout << " age = 24 \n";
+ sout << " } \n";
+ sout << " \n";
+ sout << " block2 \n";
+ sout << " { \n";
+ sout << " name= joel \n";
+ sout << " age =24 \n";
+ sout << " } block2{} \n"; // error on this line
+ sout << " \n";
+ sout << " block3 \n";
+ sout << " { \n";
+ sout << " name = john \n";
+ sout << " age = 24 \n";
+ sout << " } \n";
+ sout << " #comment \n";
+ sout << "#comment \n";
+ sout << " block4{ # comment";
+ sout << " \n";
+ sout << " name = dude \n";
+ sout << " age = 53}\n";
+ sout << " \n";
+ sout << "} \n";
+ sout << " \n";
+ sout << " \n";
+ sout << "global=hmm#comment \n";
+ sout << " \n";
+ sout << " # comment \n";
+
+ istringstream sin(sout.str());
+
+ bool error_found = false;
+ try
+ {
+ cr2.load_from(sin);
+ }
+ catch (typename config_reader::config_reader_error& e)
+ {
+ error_found = true;
+ DLIB_TEST_MSG(e.line_number == 13,e.line_number);
+ DLIB_TEST(e.redefinition == true);
+ }
+ DLIB_TEST(error_found);
+ }
+
+
+
+ }
+
+
+ void test_get_option()
+ {
+ const char* argv[100];
+ int argc;
+
+ // program --opt 4 -d dude
+ argv[0] = "program";
+ argv[1] = "--opt";
+ argv[2] = "4";
+ argv[3] = "-d";
+ argv[4] = "dude";
+ argc = 5;
+
+ std::ostringstream sout;
+ sout << "block#comment { { } \n";
+ sout << "{ \n";
+ sout << " opt = 5 \n";
+ sout << " a = 6 \n";
+ sout << " d = joel \n";
+ sout << " subblock {} \n";
+ sout << "} \n";
+ sout << " \n";
+ sout << " \n";
+ sout << "opt = 8 \n";
+ sout << "d = davis \n";
+ sout << "a = 50 \n";
+ sout << " # comment \n";
+
+ std::istringstream sin(sout.str());
+
+ config_reader cr(sin);
+
+ dlib::cmd_line_parser<char>::kernel_1a_c parser;
+
+ parser.add_option("opt","",1);
+ parser.add_option("d","",1);
+ parser.add_option("a","",1);
+ parser.add_option("b","",1);
+ parser.parse(argc, argv);
+
+ DLIB_TEST(get_option(cr, "d", "default") == "davis");
+ DLIB_TEST(get_option(cr, "opt", "default") == "8");
+ DLIB_TEST(get_option(cr, "opt", 1) == 8);
+ DLIB_TEST(get_option(cr, "optasdf", 1) == 1);
+ DLIB_TEST(get_option(cr, "optasdf", 1.1) == 1.1);
+ DLIB_TEST(get_option(cr.block("block"), "d", "default") == "joel");
+ DLIB_TEST(get_option(cr.block("block"), "opt", "default") == "5");
+ DLIB_TEST(get_option(cr.block("block"), "opt", 1) == 5);
+ DLIB_TEST(get_option(cr.block("block").block("subblock"), "d", "default") == "default");
+ DLIB_TEST(get_option(cr.block("block").block("subblock"), "opt", "default") == "default");
+ DLIB_TEST(get_option(cr.block("block").block("subblock"), "opt", 1) == 1);
+ DLIB_TEST(get_option(cr, "block.d", "default") == "joel");
+ DLIB_TEST(get_option(cr, "block.opt", "default") == "5");
+ DLIB_TEST(get_option(cr, "block.opt", 1) == 5);
+ DLIB_TEST(get_option(cr, "block.asdf.d", "default") == "default");
+ DLIB_TEST(get_option(cr, "block.asdf.opt", "default") == "default");
+ DLIB_TEST(get_option(cr, "block.asdf.opt", 2) == 2);
+ DLIB_TEST(get_option(cr, "block.subblock.d", "default") == "default");
+ DLIB_TEST(get_option(cr, "block.subblock.opt", "default") == "default");
+ DLIB_TEST(get_option(cr, "block.subblock.opt", 2) == 2);
+
+ DLIB_TEST(get_option(parser, "opt", 99) == 4);
+ DLIB_TEST(get_option(parser, "d", "stuff") == "dude");
+ DLIB_TEST(get_option(parser, "a", "stuff") == "stuff");
+ DLIB_TEST(get_option(parser, "a", 99) == 99);
+
+ DLIB_TEST(get_option(parser, cr, "d", "default") == "dude");
+ DLIB_TEST(get_option(cr, parser, "d", "default") == "dude");
+ DLIB_TEST(get_option(parser, cr, "a", 2) == 50);
+ DLIB_TEST(get_option(cr, parser, "a", 2) == 50);
+ DLIB_TEST(get_option(parser, cr, "opt", 2) == 4);
+ DLIB_TEST(get_option(cr, parser, "opt", 2) == 4);
+ DLIB_TEST(get_option(parser, cr, "b", 2) == 2);
+ DLIB_TEST(get_option(cr, parser, "b", 2) == 2);
+
+ DLIB_TEST(get_option(parser, cr.block("block"), "a", 2) == 6);
+ DLIB_TEST(get_option(cr.block("block"), parser, "a", 2) == 6);
+ }
+
+
+ class config_reader_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a test for the config_reader object. When it is constructed
+ it adds itself into the testing framework. The command line switch is
+ specified as test_config_reader by passing that string to the tester constructor.
+ !*/
+ public:
+ config_reader_tester (
+ ) :
+ tester ("test_config_reader",
+ "Runs tests on the config_reader component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing config_reader";
+ print_spinner();
+ config_reader_test<config_reader>();
+
+ dlog << LINFO << "testing config_reader_thread_safe";
+ print_spinner();
+ config_reader_test<config_reader_thread_safe>();
+
+ dlog << LINFO << "testing get_option()";
+ print_spinner();
+ test_get_option();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/correlation_tracker.cpp b/ml/dlib/dlib/test/correlation_tracker.cpp
new file mode 100644
index 000000000..5ccf61c57
--- /dev/null
+++ b/ml/dlib/dlib/test/correlation_tracker.cpp
@@ -0,0 +1,955 @@
+// Copyright (C) 2016 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/image_processing.h>
+#include <vector>
+#include <sstream>
+#include <dlib/compress_stream.h>
+#include <dlib/base64.h>
+#include <dlib/image_io.h>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.correlation_tracker");
+
+
+ class correlation_tracker_tester : public tester
+ {
+ public:
+ correlation_tracker_tester(
+ ) :
+ tester (
+ "test_correlation_tracker", // the command line argument name for this test
+ "Run tests on the correlation_tracker functions.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "perform_test()";
+
+ typedef const std::string(*frame_fn_type)();
+ // frames from examples folder
+ frame_fn_type frames[] = { &get_decoded_string_frame_000100,
+ &get_decoded_string_frame_000101,
+ &get_decoded_string_frame_000102,
+ &get_decoded_string_frame_000103
+ };
+ // correct tracking rectangles - recorded by successful runs
+ drectangle correct_rects[] = {drectangle(74, 67, 111, 152),
+ drectangle(76.025, 72.634, 112.799, 157.114),
+ drectangle(78.6849, 78.504, 115.413, 162.88),
+ drectangle(82.7572, 83.6035, 120.319, 169.895)
+ };
+ // correct update results - recorded by successful runs
+ double correct_update_results[] = { 0, 18.3077, 16.8406, 13.1716 };
+
+ correlation_tracker tracker;
+ std::istringstream sin(frames[0]());
+ array2d<unsigned char> img;
+ load_bmp(img, sin);
+ tracker.start_track(img, centered_rect(point(93, 110), 38, 86));
+ for (unsigned i = 1; i < sizeof(frames) / sizeof(frames[0]); ++i)
+ {
+ std::istringstream sin(frames[i]());
+ load_bmp(img, sin);
+
+ double res = tracker.update(img);
+ double correct_res = correct_update_results[i];
+ double res_diff = abs(correct_res - res);
+
+ drectangle pos = tracker.get_position();
+ drectangle correct_pos = correct_rects[i];
+ drectangle pos_intresect = pos.intersect(correct_pos);
+ double pos_area = pos.area();
+ double intersect_area = pos_intresect.area();
+ double rect_confidence = intersect_area / pos_area;
+
+ dlog << LINFO << "Frame #" << i << " res: " << res << " correct res: " << correct_res << " pos: " << pos
+ << " correct pos: " << correct_pos << " rect confidence: " << rect_confidence;
+
+ // small error possible due to rounding and different optimization options
+ DLIB_TEST(res_diff <= 1);
+ DLIB_TEST(rect_confidence >= 0.97);
+ print_spinner();
+ }
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'frame_000100.bmp'
+ static const std::string get_decoded_string_frame_000100()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file '..\..\examples\video_frames\frame_000100.bmp' we want to decode and return.
+ sout << "Qld+lmlZhXVX5NDRWIFG1T4+OGdJbkmxAXXdHZEtpDf6knVTlRWyAhgv85Tf11KJZbhKv1dcsKtQ";
+ sout << "fX3y/9RxoGwtXxs/KaBv3IrfvBK5WFRWzOM7H11xVin5AjxdzyzgU28fRgEasu0Jvk3SaMBNM1cI";
+ sout << "ZAK+MA+qEKwBn+rkuLbptS4sUNNC8PWaqLqNQ577TiMbsEgoa1FGkZX4feP8EfvV7w8H4FvbS+Cl";
+ sout << "yJCj0Q0Bx2fqFCDaAVtlm41VIJUFS7AePKmSnVnAlYYOQ35XxWS2sjAlWZHXiEfKmWmSOTt3x9/u";
+ sout << "5l78aPB0FvrUgF5RrvyVIOSgsC250JwINl8uulOOsykmhUUjRCw81dAITDr/d2EAYmPyiYNZWbvl";
+ sout << "0Iy4f9sOJr0HnaPdCSvojI9/xdQVT3MVjHhu82UtpJ2cuc1MjUooCZdQmTn1mksdAdZtsn78aRMw";
+ sout << "P97MKVgFmYMmG+yekaN6+nYFgTXnuEnatHDszyavB3+73iWTYiYs+CDRqEJ7XUkp+F97W/hUuvFr";
+ sout << "DwePerItRkWZN8Nmnjx0Jibv2wu37zkFVnFIAydvV9GzaFDd75hUwQE5rjGN8jp4dBMNwcK6l7kt";
+ sout << "xLm5hYF2eo9sESGJqR+8uAhGsQZESUpdBvLmf/+28MVfY7Li0lmeq+bz+JxvIa/jF5ptffuTRtZd";
+ sout << "WLbJK+EXlfeorbfh+6di5CPp5/50W5zrOepXHeDfrzCIpz6XTCw4k749ajiMk5y5XUAk/gObe1bG";
+ sout << "JZeGfMezy6bNcosolf5mmg5yDk07bK0JTLGFvYALT8aZFfUTHR8+47krp43r6XxaalqH3JFy3pYz";
+ sout << "3t1IQPC2wz9FiCGBpn+UdULDwpBt0oqbGJYGEHDWgzwv8dv31NEbqez+G+HSEfF7CWs80SH3yYzL";
+ sout << "9EjKo7ANmcYWtr8+3/SpUl0Yyzn/7zDL7191rWglr3N06+bB+bdQy7J1yGueGtTsO5XMqfUEQL5n";
+ sout << "xQ2FOU9c39cruW0Fp8TDkEKM6gowBRTelXMA1w84+L9Dynheg1iLE8MSrzvA0/TlXoFD7Wt1cC/6";
+ sout << "EoYPulG3BRy/3ugzUeiHm4ZWh95YOflbH2p8Ix+5/sBZ+W5xSr/37NRYi1nQ1jFwqPdAHx/OGvfW";
+ sout << "BKhz+PF3146JpvuVbq9fTqjqYeM+qcAu1mS+VqDyJTw3IlvRUsixyJu7/eN01m08yumXP2mm4SwC";
+ sout << "Q0j4aPKRzl4rRx5PJE4qnKxmrxSa5DavIO6ik+DKR+leGGk29zEqY+UcsqcJQLKWVy3k40wL8ouF";
+ sout << "ihEPUISSZDTE/iU/4wntqVXCP9vRNYnrnXVbh6EFFA6nr4dBrj+qnkkpDxrt3tGA0Dml1u68hNhI";
+ sout << "aI2bAca+a1TXb9mn18JTJqK6tkoJmE4JP/T5W03PSGYhRDa0ddNEt06eVPuCrSyDwQ2lQVjHiF7N";
+ sout << "iHVbLJOQ49//SmXdeId3+sJ4NwRM0jquqURHrBAYwuEImtqZDgJ9Ac7iC5FDMuigc3KJ6Y3MRAI9";
+ sout << "irrbcei2XbALqQH4hsHiOvplAaUwqE2f8iaHHQrzSKdNoRpl/0rWgEU4eWcKVl7JmmwLRWqRDg6x";
+ sout << "jYDZ9Bu3KAR3llOBPHN6G6VcVx8TfP6qHb7bYh0+lKqIv7qNYUdbVNZLnfBSrgYkrbf8LmgiUAyS";
+ sout << "d3JNuR7XsICjOPdEgC5OhKHNT8w/wcZBN1T2svgaokoYxI+dV9t84s5h+W1RgCLTnEu5Lz811RlG";
+ sout << "KEAZ+AgqPAk6PneeZs/Ujk1Q8ISZ/K6pL1SBnZN2RaN731UHMYJKK4/yCfdkqGAtFBnS4vvA82tV";
+ sout << "uv2SwPvhD2KHvZDCsAVPXFQWVVkzTWKRcSXe55vgnZjF33ziAFILy9xNklmZZ/tDpZa3I6VDkNUW";
+ sout << "o5+eLuUcJRi/dlrKnNaHSsjV6jQd0ud+JB+Gv2YfV9XcxFZDPavRGkNRdOTe045rJ7QKTI5OqZ5o";
+ sout << "DZ9Olo25TyXVteyt9CwVAlLB2owBoEmni8HFWUS1TiFWmU+DupCJw60bwE9SLhR1KpfUp32Myg2S";
+ sout << "6e7PJVndER84KdqRkPFWZyJsBTXJ6U1g273ty7MLFxZYmCp7SwvtXNrPMJ5yCS5VGa7sX8xavNkJ";
+ sout << "ade8iiSs0Upqbm71iDbMCp4oBRxa1w9zMWZ0VF+Qg4HVyKdyRmtJzBmRvUmujyYFCQwMtmzCgIu7";
+ sout << "mPCbA7EWkoteGnuFIgag9P7kAzEF6pI46gd6UyOOFF44eUytnP1AqCJYHvNexViNZ0FXzgoCzHMs";
+ sout << "m6RPhsqJnQjG+KaefJm52DCfLNOPd6+rj4mv5iQeVEyNUtdHuS3ll1svho7IKMF0KXyjajXV2X8i";
+ sout << "BaHxZ25zSlogQy//I4qdHx2SlUkiGJC8jpRZ9LVmaCWGCnbEnHn3uiiwTLRiPO0G2qgbMjgMvius";
+ sout << "XjOSu1Dlbz4A4XJ5nxRyF+7uG450OJbVF6LUYujHukrHn8LADkKQxY60sddDMcx16lofSVJEF2X8";
+ sout << "pwhXS+EcqDHQ5pT0Z7+fMFSumC6kTWJIfcwXrTJDcWslF+cnQw/qmlnSjK1jnTyU5YpjyByETfWc";
+ sout << "hpFJbt0INtrUIDjOwXha0dlbC/jLXrVbW26wTJrKmi7ftD6CJSE8cZBGLXCX4zakRRPg3DEHsv8D";
+ sout << "BFwPWlX7keygRS8L6o8teh9LHlYSbFqlno7FNqKh1V7D1ERDvsBO+6xoabo+mYXOdtyVWPWxJ0Kg";
+ sout << "1qsnFibHgmqi4RFHoSMkAcHVYj9cHhiFo3DSj8sm8l6FGBQSm+o+oehamFW6xIL9ICgm7gcBQH6N";
+ sout << "BH3f6q0CorAetVw7kyLqNiEt7G3V1DRjJ7bcn0/ziYsn6dZQ6kq9gslBWZe0dp227DpameI0TliG";
+ sout << "pZ+d5+sm6g1jE1H5H6Zlh6jJ9xDMywzNFOitOdcOL0YFuzsxKXVPA1Ye9/wYqtUyJbFvO2ZqDSbC";
+ sout << "k2z1UcbCv9KQhonO7aO6qgkaRIFmPmV82R7JsHqjA7CPQC/hURfB7qWP5mzvyB8oEqtd8LSuMgCC";
+ sout << "2WRsJTQ6GU40AoOcUFDPOo/Gv99uWzDQaGgJJzIxPlKhT3EtJWH7ZiapmojgRgdS2iEAXb4adzRQ";
+ sout << "/NsD80C6PvsuxB6NEravtrBV4nz7fXq2u1mPkjv+/jmp0hHf5SV1YDE+j+EfZqNMgEMaWJfMDbxs";
+ sout << "C70Ji0d8iv7zyevr8fIrVmTbttOxS73NShBRX7mHQnUcDZFDfLJy464v8PEvwX0gr8/ytzdMJTrN";
+ sout << "LEYHS/+ZxEN3CZyr5tzYL+DdqsTY4qFyuoQOQ0brplrGc2E1LubNhGVHXoKTsAE1+D9oq81HG4VH";
+ sout << "Y91M0A3+ckyDvQ+dTtPx+KT0on8OkZzSLy0VUJ6yHVmzlzL2R2B/C8Gp2KHKk2YJLxE8DLPRkOyz";
+ sout << "ZPrWyDUWKir87Cm6xHLScUj0MWujlg/ag1CLz38LKEBzoYxCzqQ/Zmyfp3NZRi+PEhSlSj8AyVPv";
+ sout << "FOFacvTBn+dQwWq6uLbOBXJiycohjgBGxrLc7ILTp2FHmNfpELCTCowepYKuO8VnEBGlIUJAH7+I";
+ sout << "zTtM2bvgr7k0b8dwh4SMdCBSOWPfYxuY8kVy/vcW0xKeAkrwKlVuL1+HJAtUTK0p9BOWl3bi7E4q";
+ sout << "Ur5UH6CSaVzbn7QvGh1wSKbr48XdeOx/MlqvH6yKeXxT+iogx7BdmQAMOsndXWH+T+HBbmqIF6Z8";
+ sout << "qA68Q6qcooNpHu13lqIojIbbf6VUT9eG9RqGPYXxKBAdWuRDbMmklXYoM7PI4VlmBcIgq+4U9Bps";
+ sout << "Yge/Oqf6DPFxPaqG+FnYPl7GpcXHNHAsBh5JwaDAM5uKCq4Y720KHLKqG1buziPjRwUr/5LhXyu6";
+ sout << "CF1ZzEKb6w26NDjD47myrFKRihB1zVZBxb6uIlHVcEqFZhJqC0uV/QQjRUfAQrG9G804Bcf7nuGM";
+ sout << "6u+nXr1Xl+oQIRiEYueMD1T0WbiIYIIO6lT0ICkSQQjoLQXq/8KP21Yrutv3H4PjDZXOPi9Z6Rcl";
+ sout << "40Vfdt9jyqeRgBhkhloRYFOBwXLYxlb6umBcmXoT3cv/Zlh4SfQrpG/LrfAHtYFyfwoDzXcV8Xuq";
+ sout << "qAtTkj97UcAVnfC0lNrBnWCT2SieQUl8nNLoIQl9uhzRBFHH7U9ey6uX3zop4esABGV/DL1ypLd2";
+ sout << "Yu2Q6XU+1j7wh3Rn5zttubqvYR8P5jMEqMUaX2Fith42jHy0U1NuNzX/MPCm6DFLvah/G/0sPKiP";
+ sout << "lboucbKekedV/knGV3kx+h6MmMgBRC4OkkPf3HG5ewpVpe4I3SZ/auTk1ZnePM5RL5wskdGCdbND";
+ sout << "njzEv5sKtTE1TxCAgVh6iFUtvr7c+3DNDkTilcm+ILRMwEr9vCF/OGcOT3YWr9cW/eP6fy/801bU";
+ sout << "nhotDzcKSPQbbN7jd3WIe6kaeXjsBk6LIHmPjtGPT3UdRFhEJZrnABhQrasLPeY0/+dODC5Y3GcC";
+ sout << "fV68kmensUcZ/5hFSEpLsScx/OtGvFI7hLNBAAJ6bhEuvgId7OXxQgWjQ6wKDhwOJmEB1Ra/Bztw";
+ sout << "4bGdRMl6c99nGcc9GmSWI1CmQZqbNfxL7AKO1oSkwpWbK9E9Cl+ZV5XyP28AQky4KQlYBvwUDH57";
+ sout << "LvtOvuIe/HzSagQjG8Sxf7wGF+MAz7MLRtFYGkHviL+mRvtp0NSHSYDEOqaIsnk1HbTWHUj0FUQt";
+ sout << "AD14VkX9ReVi1LnJGJNwmjeLYk7keYTkksi/kKEWCkh/8Av2Rlk7oZCwODxsAcnAyXStJV0tEAHN";
+ sout << "lq7MaAJz5zWZ4ZsETA5mn+3Qj4jIi5vbqJScxOh5KCvyOYfio9Eo+DPvyJtvyjGnqVkoFFk7v+8H";
+ sout << "e4d20Aq0vfYGKPzVNoXAtOPuA6/d/2yizrl9gEPBGVw2I3Q1/XlFMIHHZ3yT1TGJfGXcVkrYRhDY";
+ sout << "s8k6oEKbp0QQUiSkercwxbLpSMblFDaGeudPcWzKVwPE52rMEzh1/jr72s6ZUd/+Os2b3+CEg+lj";
+ sout << "AlnkU1tNZVnanmzOb5xBnk1H+3Q+FppUe9MgOK73344O7QlbBklWclKizZIoRVaOeP7WvjXSJK/A";
+ sout << "PPXXyKLMwP8eYDDPKOTA7MvBH3q4r7j7Au5av2sn1ZGwxBHLH4aYFH54kXJa5rwl0TgsTAHsQ2+5";
+ sout << "0/OWixbr8Ysl2JxunMjcewhJFI3mLHFmsYfVYDwC2+hIubW231HCxvqI5BgWZZRU+9DZ2hdQ+orw";
+ sout << "qocOI3yK5uHs6Qaxv9HPgWzNXLG4a1h2C+RbhIFMGNUcDAGrCgBCgepruLT0RLuaSYrsZY/gWRwj";
+ sout << "krk1M69/lnwvZlasFruau26RLyMAbELixpeeGpztv/tJx5fqStsjMGLHUsRj0SKgXgdawRdgUXUs";
+ sout << "Hepp9HsmJ/HR+5xAv8ORiEQekO02b/2wgqGTYXyHGT+RP9f76A90kVJ6Px4njrOLrICyTUcIFrIh";
+ sout << "0AvbAEysPnxbtYcp5tdNbG2RuarygtgscOxERIa1NaunqnBouzW88mOLeTgBV9Ofh2fvX3qalfcs";
+ sout << "xYY4//taBvyKWHiCanf5drYyOBPm1m8uzNP9ew6K6IYC6S4m8aklO+NrkoCqL2sq6Ged5y1nsWws";
+ sout << "BLeSaCakjVDU3ysh+J8YamF1Tzp+cOfh9dAquG4sk2jJmSfgl31jtG2lCBkBRQf+Cybgr7QfJYGd";
+ sout << "ZoX4RLzmSK3BXrufSNHntV7dXKCDT+2NvrW4n1EUegwonALERWRTMRDmA2NPZYgqr5cy8v0KQr0V";
+ sout << "hvEMjqP/9SPJdTtbjJY7WtdTNU5Er4KdzasYcJjphAPU3zC5PtCHbtTVUGXNz1UneXnzrN13zlK4";
+ sout << "WyJ9UcXeWpjtztobQZ/8NwXiYOndZ+/qF3BdYjHYDYhSjod4JyCnmLuy+cVG9yB3e21XVeUVC8sh";
+ sout << "7yg2oBx+9yn1ZK5ResSEAmX+m6Jq0etJWVnYvnl6TSN0XAFbZRk5n6r9w443Frw8RVRfYyISbuTm";
+ sout << "oLMaClZFf/XxxvCIQAd6+IDMzukUDvEKObp2+rbf7IWZtDUeR3VpCp3CJhTMr2UBRC68fwB3mx/n";
+ sout << "C2pAyPNX8WbZ8ZpAbtW3ax8U+yh2rH+hEK6zJSXFZk0Ea9Yc4MNhtDqGEXLgBvPX/OMH4E5wJxTP";
+ sout << "H070u7+OQWwA+Aeup//kJ+jm8EqF2RTAyGCiiYl8JXAMNBdIGaG+kzb9RzRD+YiyOrV/WyXn2pFv";
+ sout << "68NBt9sunIBnzNMLCPzT3lb4DcoOExmoOjcrziN6G2HjRsrkmyVnjvgoWO2wILYkm+yGy+ZEM1U4";
+ sout << "MpVYZgXikHOos/FR0GG9H65gUCPthPn448mtVNFvuYJhhenvuuSkUWI2IFW+rhEeOUXg+r4ZISpZ";
+ sout << "F26+EzKiDYKJWbJQNrVJv7CygE6SZ6E4VnKuXbzKHDct3O5EHoE3NDCO7J5kD7RyFE6HgUXusSgb";
+ sout << "kH2DOgJrK8KXhwcDIH4AmrPFukCmgS0/yTWOjiZKW8dmp9q9UHKQlRf1rqgmkph2fGXXBbi+AMLd";
+ sout << "qtk8gsm5Gb/a/fHIg8zOJ295ZShCqWm87z9jK5lx0/kFZKraB2JleJ0ryPFXCOp60hUbSvzzfxJ7";
+ sout << "JkH1dWoRvWr3wpXrwZucfHH11AeFRe3ShRaAKy42+CclzPkWDFLnJQt8NXSkZeuoPjcx9A7lI6UP";
+ sout << "WfwYZowJkoGDUq//TSqzSK6XAvQBUHuviclx/4/C3BvCwu40wXDadUtt+2xWJjNNvMlhnoPY3/i0";
+ sout << "yKS/BSg4TsdTceqfkt0nU5FeTdyfpLW/1TOAFERXkV2bTkEnoJ8g5LXHqj58hDZRnO45lxDXDYvX";
+ sout << "/3G7ja5OfBA+8flE+MDTtRnWAxgUBDxlFEKD2T2RBgQlLcy0Xa23LgAD3qIWYH+o5UVAmVoI5HjL";
+ sout << "mJ4FxQdvJOH7VwyIubukaioVoB63Ls1ySl1Ysk7EdgCpdiugM6I39QsFlYeHE3AlLeoHn4caWBFE";
+ sout << "lWIhgKer7kBvPFG7M6bN5flAtzAbEXFAH4M35L/6Cl+O2h+BvCJFiK1W/LZw2pkc+Ie0xC0YNWSn";
+ sout << "5nAPPxgGYtxCHLVl3R2XJvBcPpAHzbc05fAp2G4AKscWc75SZwfayKKYarX2U+zu3PVJIYbioSqD";
+ sout << "B1b3Wq4vO7MDdD7AMZjJO1ZrX3+8piEVo1MeVbqZBy3VTbjsnkkErQfyOulxlQfdcblMj2Zn9NRg";
+ sout << "EQwOnGEsWulIurqEe7bQEZldvTTz4pTOZ2W+uv8TqfnvtKgNESaqYvofF72ZFSJ4rMU+Z18Fqaep";
+ sout << "5MitEMIKwX3ttFQlgM4/CWeaygkhyNMbFA2C/T3jIopsy3bPo7AwwhHxaZIo9ghkvt0nTP80dgtU";
+ sout << "DhP2a2tg+fNUkvWFSfdP9/NKyH5Fahlm9UPNozDehlI0dzeHvqSpdYFYuTYtf1jggNVeC3r/Zfq8";
+ sout << "+B7U2qq+e4iGW1KVkOlimC3tYTRfPj4ZILtHAUIwHh4HY7pTxxpErDLpxyEZJNkBUxgN0hPLm8UN";
+ sout << "hTu3qFXzB149UpZCv/JmjmmEgLAWMT3PbBCebNVPEjfO6I59rTOvl+fVD3X2UJM1It4mh3NJPHzj";
+ sout << "4O7qLNm+S+A00bZx/g4ncCxrCvFkTpBmt21ZMAI/H4swFDlJ0gzKTq6+nhI/nbiWsuRY8z+GNqcE";
+ sout << "Snutk54hYXlQ3tVAxhRY4srAcEQMcHjX8pWrJUZjRiiYWnVfnmUf6U3rki8P25851GwTUGB6/lL+";
+ sout << "6MWKQ+s1Sa71hc5icdJtxTJSWADg41KO8n1xQ0Pu0KJzvdNMM9G4AswY87XnASsaF9EXKDTSW4q/";
+ sout << "s601Ghu8vEYKQVBNfJdiZ0wPsaLM2SvRwSS4Ji7agaJRLBvcv/cK0Hrxml20CNIGS2Q81xGS0Hdk";
+ sout << "ykMptYe+8pClFugfpJ+ETSqFgclYc0XoucOUxFh0vyg5CVE7WX6chpBmdhwWNnoyJz+WvNcoPIu9";
+ sout << "UZdYaseFLVhArb8cVaA9Mfk7tmFxaxNeXsIBFjiE4dcWKJbZXMnkhCaqG4k3SIHsswxjtj9hFoTB";
+ sout << "BzmbIwFhxPg7sZVrG7Af26CYC01P2PGqNqJnZRZQt1LwtPVQHzvMk2v0r1I3DDD6ugGlva+PrHIP";
+ sout << "D8FCY/mc0poDzTANlwAx28hkPTbtCpJIrWScZ/Vu/KYJo3F1Gk4C4CwcghgkwTYLhe2eMwlnA+Ww";
+ sout << "vOlw5SD9jca7GrTA2tkTvsUnlskDgGlkAvEwc6N5DkS6clO1XRbh1mwhr4UwRhkR9Z8sQLLUv0yt";
+ sout << "N/Wq4i6xuXuROdy78DSiSh9Gis5XQbqCvf1VKUOKkaA+/H0Y+XsrHrRCcqE5uaY0iIZtc62XgVHW";
+ sout << "QyrlDHsh4Lt9qGD93Dx2EZQqyl8KoyhQ/WbgnG/s77zdSNGTkoJDEQKIrKLRk9ReptdqQzjLPJvf";
+ sout << "GwN7wgO2N68B9XbX8hfXUmHX+G7kVnncugQzg0DS1qQ0Hbp4ibZHKEAUHtkoPEVgzGcsVowGYCqB";
+ sout << "KCGaq6FqyyIYp+UO5j00xyftvh6uta3atuu+JHkWAPGKY7uooV3MGmdcnnF8umE1NDEBfrcWrrNi";
+ sout << "IzQcnZe31Nxqo3WsknqYpRvCDwUZiU1f/EidxhykoQ1NCo1CY6ociQna6kpsM52E9ALvYlUyobN+";
+ sout << "7iJQcfagbJw6OpT+P54HFsedkIAlBgTIfZfag1u4lKZnibEZ5SEBfOGeI4pemf/ST+4a+2GalVHc";
+ sout << "4W5T3xhuJjQiIeE8X2/nEwqEPQRHdTH109EW4BCv1rlh+XWqRXQVHPOYY3lVV4ONn7/iWN0fslOG";
+ sout << "z2/MghTZb7Z1MhiWLxTcwpUXoyy/fexdBySIUf2ukM45ZPLr7T1aCrc+pW+XKfTewxqhWnKSjpVR";
+ sout << "o4doFMv+eVk8mQPFjAP98MdIdYEgTakSQPoEdHijyq31ID0lI3qDPElGdFEq/yKpd9Tg0i2OaOvk";
+ sout << "BiaBfldrXL+7jlCSTB14Vo0RCiGIGuxqmEgQhUrT2iHV1baKVWUuKERauwS3jVNz+xq6PsAU9lWn";
+ sout << "mC1WbmHOWyHpvoxE/X3X53njIVVIbRnGwEma/1THUaFIZ+qb4UVfVqBXHCiCtyAnf7+aH2/T52Pd";
+ sout << "gayp9h72ofbN/eBLbc0qXqECKcWLvwQlgiUkV5490CkjKnf49ubdFKRRH0PKCi0CR8T8lfhrHYnf";
+ sout << "j29CDEgwX3LkIPw9GXt93ua7XgOilyqxhPm5vDXFpfgR98Y4iMUyheHms8U81xbRmM7SqAPXDJsO";
+ sout << "vjoNtHmc20hgCb46BUQbMQMe/hhDjQNFMQ+HA83cvTyCqsXVdKcWIw3vPfD3RUqZ1R6LGgmLe+Xl";
+ sout << "vS2S/uDJjBohq5pJ7xCSI2+ylMf47qtS1pYd1bUXssnpJOu3kplTwqW5idkz8l01FlR+duXcn4we";
+ sout << "Wop+0ncMd5AsBpk2j868TAPVEJyC2lyQ9Qm6OouPEtMg4x0jyANl7JhyfEesTTvxIm3GNFe0fKTT";
+ sout << "cFwOojUje215zqgOqwE0b7JkipU4ssQ6j1lSHuW8lWEVKa17Wr2B77lj21JxubQJ99iifjoarWGs";
+ sout << "5NX5nxCQKJGDEPagDVmL7TZaQj+Cp34MR9mCJtRTyLmA4g2rwARMsbq1btaKXUG91484ipcu2jot";
+ sout << "/F3wLGdAhXQFWrxhIJS0ORxalPcSZ01zkECazBTIMokBrneVaX0RulGEMrs+CIGiSE6pFJKX18xs";
+ sout << "6dGqxF6TkPk3GalrQNn0al/8FgetsD8zUX+d5PdqOpb7qNqEfHAClOcNxhv341nNrGnR7YuO+r8R";
+ sout << "67gAjqnan2NY02JmVhT7xqN1Uz9jCWqmbLNAPDUWPvVLvFtHAqqp556xhpVhJchWi81mIZJ3S2L2";
+ sout << "TKd+jGHjojiYNyjQxz3DD1S6ZN4mPgzK6JMC4txgvcQ9qoWhoqBDRDrj9s3lT5kkjZnHRPO0RE+s";
+ sout << "W6m51Z6sKMT1/yoneuJEnrwLxlD3Efd/cq8zmmUKREZgqR0q7WkXC1Tfs5sPVwHDlc45p2ejbze2";
+ sout << "iDEv4ULiYrNnj/wdOSwVnNt/1DXvQ1FLtJ7K/Bt0qUszCNnNu6ZOwhOM2bqVugcOvONb6fLNOzY3";
+ sout << "WYA+2RGS0nuHC/pFuzX/AQiRveFsq3IqtYxyexv8uxmlg4sPDb7Q8i3pT5fQDYAh6CIFX7mCITvy";
+ sout << "2JnjSfiVqGdITtvsHyJtUVO0YlQKUETRBzsUQ7bvQ9gTETskkHNPe3h/VR/Dpa6ukhyspf1G9XI5";
+ sout << "bobOkgu1/3ExBOTiCjbcxgGrgXw7VdmFURpq+FAQwuNxLDSoNfwFw6ISgP80lgBDV8/5l24p517f";
+ sout << "fvNPTCus2I2A//vLxMIQqU6cz+kIeViDq0fcTxoBiD7SoISwJiRTqciiJ005uVYFAisBpU06k0NJ";
+ sout << "NQf1DfYz5JKAiP05ehMhQLCnJaHjbC3yILIfxXYu4wEV2lfLWWZ2u7/0oDBaZKNHv5JLzjQglqBr";
+ sout << "o+0GHf/hhu1EEqAyFRPWruxhJ1XzvbLt8sHc6wsxkQCYXPGfxlz5+WMrSdNP6jPoEleH7xcL/b1r";
+ sout << "mw5oP8fsoppeoxiK63Td0Ut6WtCI9grmCKOYJt9UfzTYI4TLDsI7mtofZPUvX8IeOOr8LySclV+m";
+ sout << "AcwU6BJepTxRmINnck9tCe7m5unJI8nBy+uy6a9NvSILGvuoJ6bidAqS0dojvAV9m1smC//ZJPLJ";
+ sout << "8UMVkhMUHEgx8n/Ss08rQXBFFqao1rCOvbUR1XC6g31GAju2dLm8Zyk9eomFmdOdtRTobmK4XbX4";
+ sout << "mNwCOlbKSZt1aBDN8JLYBR84cEBB4sjsPEXupIrJyKAe306c3RrnYj5lMxvnnknMqIfllkKr1BOm";
+ sout << "kBYJ91aDe10mUd7zHQwW8KAjHI4pmDhLwusleQcl0RL2Q6CgOB3x6ZaYnXLtuWsOf958+niS6dg1";
+ sout << "RA2Lv57ajSAOHzvuy7h/WV6uWhfsikjw6TEci8rQ6v5gY2DEMjrtSCbJeiJzcIqIC8bz4lvmEfiV";
+ sout << "QpZPhGDgfS73qeZV7ljrfBcjvSuN9MPbMFQfkr5v9lTNJ+/AosXAjqM6aJ4TTrMq3XAYMcbuEaDt";
+ sout << "89cI2TabaBe8B7cniD+JBOu73fndg6YglAy0Cl41GFjU0u/xq0xHIim7e9TLVtTJE47CjTWRrBEX";
+ sout << "ZAJLPDlnhevjsz+0vEuLeqGnsX5yjbmtZzpkDvh+R6eZAJiBVq9uOLHbKqplwbjU31y2OO+Gf2Sg";
+ sout << "C8nczxwSt6JT8ktG3CuGhuEIGi4l5LAjIjYd4LpQVcsUM/vP5cbzaC7/XyLmSY92KfBD8OuUL6FJ";
+ sout << "kMNyHHEtawNcKlUWsW6N7ybRpvZEwRXhQP+5Q3QXHDbiQ9YJhvnnLWHFJx1TmMlhAQlyJBnuGD9q";
+ sout << "Re5kqVi5ztXFHLY+yHAFHgCVbGq7WS3xxwQD+jeuLEnvbtNF5qUePj7u7psaPpYkQEj2DvRBoBGm";
+ sout << "eEheol5Gc8NcW8wRw0hLr3Syw/8b+1uMl7c/Sxx08yvnB7e8JNQ4kQMkxVWFCWE+OXKul5nI5mBN";
+ sout << "HRbSO5bBCuYU/9P7DvvK2U/WmcnOvNuFFax6mmBc7E8nqao9wKmpypDvddWJ+aStllc1xZt875G+";
+ sout << "xrYOX7Iv0MSfk41j+VwrawGyVYKLrssBQoft2lbeDqOsJBgxS1wFmxQXgFl5pW2ynnye7GuR9A+t";
+ sout << "pbgKYqFhYg8v2ZIYJ/SDJey5H6TImYlPNriXZv/ocn888rvlfOBjDcG9KiJ/CJDLs6RdMMI67EOE";
+ sout << "5VBRISu61OMlhv/zp2bOsyvONztlHXERM+N6zViIlmbewanZ7ujo969A8Edx1YiD7eBR9AkB2VxW";
+ sout << "nlnX2RzojsFbKIQjuE5NoFZdE49PsauvRhzYBid47XuPLu48IGlVWuX8dUENwWe8d3jUb3c8BPUv";
+ sout << "2E2TUEOcbEx/b+q5ex28LRk3CL2AolCUHMhw/aFKOj+P+AJMC2qAgzhEkVUWLfD5oHnN0gFzIr28";
+ sout << "EONuinHzkLIW/FcvxqVjNBn9O6svsz1RGQ7dOUStEjwpKDyYWboawNC12lNgh6+JO5uA9jGqmSyF";
+ sout << "uBacrq7GoETHISP5/7Mc6PkdsT3IQ7iy+suT5vTybsqlATrvJCR2/6S+M8kZCJdkIN3tVrbKqKHf";
+ sout << "O5sHBb6MgPVWotsXQyZ5m5t5x2bquGfonmlEdOcjBpYJSEM9Gd+8zvt36NgjRRr7Zgs8DU691FOE";
+ sout << "eoOOYDfc5yzjHClH/b2k5po2saebjyh6Zf2/EC5mQuqkHEeLtRbxSDSa0u5jbh80vEZ//J/3nhsr";
+ sout << "lL7Am8nXsj6aqyEFVYnomyDo9Uk+KLWD11PqLqJiCNTnxZbsCwiqZDo6qo4JngJbvdbGZBQMpgzU";
+ sout << "kj5cDYxSZLDARNLr+/M49l7esBKTtJUVtgJX2+nejrlgeNAc2BwGQPecI9Zx9v7qHOhxSsCwSrGG";
+ sout << "ZrHrTT3Pb08AKSzLQLmuijTWBRw9SmApDxTcUnSCI3RGTmqueOtpq8hGzD07OFhFU62SAdx8cW8w";
+ sout << "oB/FAeZGOpIHY3hi47JXjZGTw3oGMtUkbq6RN6wQ5NJzij/HHjLzXyXKpd6CveDuxM24zzyvhEwY";
+ sout << "Q3FNWhhgi8RcIFb5VutGDNZ4cd+jqf/veLh9Q1110CuDpR7MUUWm+MlG//rMcScEZDOZORL/qMuw";
+ sout << "+aKT4+x2LXKb8G5uWwNovb3eZOJDTnb7Mvp4RfFql4X38BUjUgjZEAO5QXRPv+OfUi3PeeZBDQO9";
+ sout << "yjqeCNsecLNlu4cf222h7Et1rdp8zYPwMbdfLrI3pH69VxM5eSJ81OtprdbsO36svGkPOOB8/rNq";
+ sout << "Lu/xFCLKvWnHCPoGT5ng1vmcUl6Lkz3r+yD3+Uy0X96++sXHnOVdiWxKyRhew+3/gSQuM6zoPumc";
+ sout << "xzAkEjOiKghShOmqPKQzrsEUi+sZ3NnCBwRyUwlaFw7/Fp1pi/N/9bCX30AEfaD7ucsxJGtC78W1";
+ sout << "jWxi5K4qPpgaM+qU9VORlnJRFpYFBgu/nqvd8LkFrLkLsFDxkEO7bQDjEKX6xTltM7nbF/KVSasE";
+ sout << "OXiMk4x9aOa8buelZrRiANp56cidcnJ8Ayv1GGAaA+hNYC+BNmTXZUal3NyMvxJOzFlKfaSUbgNB";
+ sout << "EsYQusXQuVqkD6lW2Odx1Lt3hHzF0MYgMY3cuw5oeMKzarQoA97JDf74Lnp63MeuU+pjBanY5pNF";
+ sout << "9D3/l1UIsrFh2ZyC0vS4i+5SGDI0Fza9ZsopX14fbUOG5FFSkrHPL1ArMvIXAG7B3OPSRF9ChX1u";
+ sout << "uPCaRK+0JYxLdACdJB4x+Mhnv3fS8w5dDetUO2zy6swM2OonEXqln7lETWsBk5yQpXBo9sR8RamA";
+ sout << "nt4HQhwaK0IAX4L6p2LMKJ27YUq2F3Xe2PWf9gMXdrUQPTvpq+MdEnDIJYf7sTkT+lyqLJJZap2y";
+ sout << "jmuv5U6uQyaeJ2ayTd2TcvryYtrYg4dUEfTvjdlE1QdJPxUPCzjbkM/y9/SrfPCXsWVlDZDtytup";
+ sout << "tSK5GBlCH8JOpiiwgyBR5nAHNZ8SKP/e0K2Ps+mDx6xcSz4WL6loJUN5+lPuMHYxXbT53LPOqwNX";
+ sout << "nS+OCDPFclYZO/0TxEerFNvxvjXLU9VxB87zLZRV24VAztABk3d5zrY48iSZ8WDUudPF0mf39geE";
+ sout << "4j9zhG2/3+rc1yYFhAQFN0ch0G+Gu/mEEkSkxSZy/PK/v+ITne9JIqao8JfEVgwmQY2VCSyy4Rj/";
+ sout << "KHb5SOY6CDIWIRMRj7GsqxI=";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'frame_000101.bmp'
+ static const std::string get_decoded_string_frame_000101()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file '..\..\examples\video_frames\frame_000101.bmp' we want to decode and return.
+ sout << "Qld+lmlZhXVX5NDRWIFG1T4+OGdJbkmxAXXdHZEtpDf6knVTlRWyAhgv85Tf11KJZbhKv1dcsKtQ";
+ sout << "fX3y/9RxoGs2WfSxuQ88PN3jZemvW7PfY1s1vwY1Govp+hD6LGyg6qbJF5iSr2edUHLWGq/00D7J";
+ sout << "dhKHu/QsLpEM3w0yjnufc6hORX4GNjJ2a/k5xFnHf29G4ztGVp6OAlsQa4tcLsh3cOK/eyCjevG6";
+ sout << "7GaMl/sfkK4TsjNfqdXM8sWxBCw/r6JTLrvlzVxDTmu6Sm2MpQ+IrRXFn4gK5vwPmc/mEp6etj4w";
+ sout << "YeFI6w2jGVTFIg3R3ixaPUtvv+gaIOtPsF+4StbI3AlmD1kDBt0t2xEyPOsmjOBuh+oy/si3xWt7";
+ sout << "RlCBakbDZnIihbzDMrLwTJvgoiQDgT3U4JRpH+5cL8E/3M5JAOuKWJU9nfdtNVIf1NuHCd1Ajsvt";
+ sout << "LjRLI3+rqQErHsKre5sId70rx+sYSqTWaiiGi0Nwg+JdCRuA1OwFmK4rahCAEjFr55py0iZxFuo/";
+ sout << "r9DLOVGqKKIWDX2HQQrQ8N1gATa5Wh9ypd1RWKz0s1wghRS8nzIpFqtvXxJxYz39gjai7qUOP25M";
+ sout << "zEL4RlnFsqP7GJaT7YnpV4PLkKAzYoq2SMTq4nlK2MGohKoPNj1JCfVcq3syGMJNYtNNOtN1m/E2";
+ sout << "3AKUnpPX0CAEgA43Y5yMLR5ca4+KGlvO/qWwex/bcU6uZSc6uEh2pcVaFvlnyUYdZlBg5huymL56";
+ sout << "HojkUQWiv48vxAoYtiEc2xsgsD/HeJxF7z+kWJ5nDeyxLhCLpDZfrc0g76TVEOVy68CtdGLuhDe0";
+ sout << "dhFhj+tlkmbNse+X7PlhhnI3Oq8kt8tFJly0YH9RXYd2eQDSK3Wz88jGhe9wcBEwcFir1foxdRa/";
+ sout << "rj6qz9DeAo6bVEZkIEXPSXL9EmiyTxwqjHgIySK1il+csxW2Gpwb1hwlKQWr2x7bRf826W/DGplc";
+ sout << "XNLAy0HLzQh+8E1iJZhpCwYthe751RQLrYaBxlFNZtlHDKIfuGg6ByiFdr8y3T9dx1e4xJHHAEhE";
+ sout << "Aem48B79Zp5xD/ZZOgAmJx/hrXJCnYXdH1/5FNhTyySNQKG2fChxHwALxDoOsB5BwFP77RkEuXkO";
+ sout << "QWLOWFUtu8XYAvf2re0ZafPDonS/GoPZkMBWo4S6KNoczfDskSXQ4PqKAW2stt1K3BoxO5LXfQYG";
+ sout << "qepdQBcZfL1Ir2WmA0L2HC3UmFr4bPwVkzaYCs4uQJqivpw1lD7CcNKi4BfBqWFTs0uWXQrwY1Yv";
+ sout << "rmhEavMquYjJRdo2QnufXkSjrW8VpVEthiQK895ABfggCWg4F3yiqBlCR+aGcCetNoJZ9pS3sb3Z";
+ sout << "32tmtN4rrQ4jMb02QNnXPQ+vAavQaWok/dELaGYCG7PefjjcFqX48WNVmHQx+wLW4m0xo0mqXSxz";
+ sout << "SQakpCGETfxuzyIlmYVRh41QcDdd/NH/CIwIMFVyga44Ewpcuew5mbz7bXP3k+FlxzXJ4e0ABVn9";
+ sout << "hO2sOG1V8teDymKMNPQOBuec5AenB+kchCtCDL8ZtglpBBqmijUCegyxiVpjnCzdGQvIq1XdfVmg";
+ sout << "e/hWiXT1Vi0+1wtdL3CayA1h+zvUiIJspWD5QOHj8O6buKKWky+V2UZDPK24AuIl125ajH481E6H";
+ sout << "sjS0/FqKjHWfw/SayHcCdbqIt6/8AouwlkzGOK4C14HxAg1jmvGnRn+46SCXNjlHBDH8/mJ0Z1uw";
+ sout << "C2Fv6G6t/IX1hcjJ8NBQOY/3gXAtDRmkNUc3KImzaKNDUkS9N8U5QLFVqrBQ9Dw2kjJfc28QJcXy";
+ sout << "OOItYP1RQmG942DKVwW+QQV/fvK8BFpRP5yuNgmzjGZI8gP5cqIOkW+D4eBFBb8PYsa15fOF9AWB";
+ sout << "RXDztTbO3uXWcTpa5w/dSbawwBqfeOY5wh3lnYd16Q+Yorn9D0O9VGFWr2JqKwl/NcRtH5FFsNC4";
+ sout << "LpqcX12SoO3gsql2isJzJlyTmeSDB5C7o0mBE23CsBx9uqDwBJn+YAucIFxB6I4sxgF6EOilkA0B";
+ sout << "5CpLkspGnHs66pvrLeByoDMCpkt56bXRlcvFhjRo5nljY+GjBh6Ux3ZJnMdUG4Qded7oVaY65JVX";
+ sout << "MpoHUUG/VSR8FWuHUP+SXh71QiEjsrAAVQ+Fm+fAH3xQ9Vjiv1ffRvxkb72G9O/LjF6NWWgowFcj";
+ sout << "QBhuD/mTI2q+6spFLWlZk9PmCWTBkQGsWouyZMuVQqr56sP0UEKANEGwpq+h3pq9t4+eN8WcGhyd";
+ sout << "kKgOgUvt8aY7Ib1HdckQt9cbtOrYyjxrQ7o7CXR8eg1SLPDJoWc05YevckkECeF4nQcZvoRxOlEV";
+ sout << "rQwpnngQ9oNoREpNnGlZGtBr97bvWTw3UWwiEkqDJWTTbgoDSzjEroYV3RjVyVKu7BZRTvWDFz+/";
+ sout << "xohrwbZ/NFA8wGZpgm0qtJRMCyDUIAJuQSEjxa925hWfdkVJxhExxXgWp7NQzhawF7/16Fa1tyMK";
+ sout << "62nnOYWV/OWcNOrRCt96RlQooSf0DbUqtLt0f6AzkjKobn3qpkaMxg4Fwzru+BaLmId2Cnsqdlvu";
+ sout << "jCjsgpY9cfv7NdcnPvhLSPyykMPmBRe2XZycAzmQdpY04DpVI/A7gpkVyH3IvYP0ZC4SXNwt3Iht";
+ sout << "CnmDh+VF9+iVjlaG/JJ2cSXG1mDSfjPgQqEO2DtotkjN3cHmqqSkLqbmA2PMnbzCn5FJbdhES/C7";
+ sout << "uMRFLhsEyH7BF/UGHCyIkzbGQhF1q3PE1PP7A6UOtWr9tmKvctlDnsiEpGvxBN/8wfDERqImT7Ex";
+ sout << "f/0fF7UbHD1+lJc9VzXKeV2ZsFhFRp7r89yVcejSwiAcgHenFuvMEtZ3lgRqy7mFxwN7KNAh3O6Y";
+ sout << "RqGFSz9w0gb2gmX/1f7kVvoKTgibMHYXyHUSvusrjX9betzQ4NysjILBta51/ZbeBIZPF8V7mhNE";
+ sout << "5c6iBo4j1i+jEzBGCbH4jGwNTRoD2S+uWFrDS2x3hYJL6uBoEWHN0oG5f7H3I82zkju7jkuUCM7V";
+ sout << "bd02Suu/hjwDlr4YaQUTIo2aThnXT7ZgCaNhkWODTVU3BqX6M8WP3zFZrMWGtbuXrE6WdweK5ENk";
+ sout << "+aV+0CDcPHertb4LmJCOY3yXtPe15OsDHwedxxBJCt4y1UdamFtFo57XjHeAr5c17B/MWQ82/ZlW";
+ sout << "1Rwrm+gNysxVGgfmzvmT0hpIiE//g/HqI737ovjOo6yRfkjil8AqIlOT8Gw8mBbnME2OyjX/TPOw";
+ sout << "wX4F52tAhs3oi9HmaKHW//GlC7ILPqFN1Yg1azmvTgqVeYq3l76JbgZwNmPUEM5z/EfOcWu1GKT1";
+ sout << "Pc0Hz6WcPYYyANIlmv32CkBiZQwMi5AIhrUJvpGaD16hPW8f5lXO+oG3FSJlhZhiIQVKFX/8UqZk";
+ sout << "AzFhmyPjUHNHOsJo+1c+5FTnPsjHDzYwW5fUQRSz3L3/rv6AY7g0BXKLmxCJYzIwxyQ5i7z810d0";
+ sout << "jTPy1DANcssoEqdA0P2u6udO3d0rtL1AY7dKoH5QYyKrOjx+HkLZcfxX2lpjp+kbq4uy89JYfo25";
+ sout << "M4tX0B45FKrUDDtIPKR9GRfb6VgsH2bi7aediwVXCoaTxPNgUyKaFWSf+y9gPBiD060TccAZfCqQ";
+ sout << "HqI2fQUwEfsiv1XeTLGH8mNIHETMKP78LdWLhATM3ejl8aGcNxsRAbMXm9JgJmuHxaNViUdWmfPU";
+ sout << "hJMksO1JBS66hcn0jBJhZEYF8qUwG855G65k8Vvo8tihDIbJhxGMDByP1beBLs6uoohknWTtDU0K";
+ sout << "Q70nziEj+VDbaexOU+dF/b/ywH7Q+KUAFvHH/xObyc0/maoRS/e0pfyhmB4OeGsbWAs9aGQNIaAn";
+ sout << "Toh1zF+xQBFMKGurc3P4aPvh3Vo/cw2hQTMYJpUJQvhYx8XAnA+hRtnXZtHD2Jas88G0JXCCX5EG";
+ sout << "9te/j6MEP9Xwb/TjVLDGOc4IeMYqVftVFcmL9hrX6nk3TYDyUkvLjgn8vXEmJ7qB8CthBF7UUyjU";
+ sout << "mcz3agjf1/6xrIotky+zbEAy45LvmZkcTfVVJt5nVyir5hvcGyXWUOpqp/9NQr0ClEVhzfD2d1cd";
+ sout << "xSSLaeTKsr0jTWFV9GDeIhprg4lJhxL/HbxFu3iOocrysDTTxsbLSTjO33ndrGiz08uW96K1QY2F";
+ sout << "lqmK8FOhR8C1eaUdUFfIa/cINoThxQRkoYq3tUr313+VzGTRO0I2SSJMIHgFBslLDHwX5AbkpJPs";
+ sout << "7jCQESWTp+LDoN6g2X+RmiLlPQiU7iJXxF7Y2SU09kmHOg7HFPKWZQ8bI+m6CG7kvBF9lWNuzfr0";
+ sout << "lWz08lEMExIEAAngM7G0LqqOuLJO+Dpk+lLWjO5OICoxQ/M7akvSJHtc2mVOhXNskHOYG7ZtEEEd";
+ sout << "ceDN4bzzJ6qEuYMljZcKkh3NduZbETGnW7D7Ec/UqU6WNX01iMGt+4lCWtu8NHySWGqIXcX+8ITJ";
+ sout << "euDFM4B86RSKk38VpVUXXLWd9GPUYa795WcoVxHlFRPULnHJK0G2/AUuKe/K3CxHNqnxsk1aGdxS";
+ sout << "NGVyQfhXJBWBA22f0Eclu/Z/UdzpKZjCZFFZWt/4ppIWGyMvxheOSqjA55keu3QoFj+xhE0TUNlv";
+ sout << "cYMT/b9kHJnHQ+j9X7ReicHMNdtWYmzybolMFV5P8fBwlReR6BS7nAk7hu37K4fpKoKujfMUfE76";
+ sout << "PYTfRoTxKKY0atJg87ZhID745jym89xIqFqex1vqb3Ysw0+dZDWHbwiidUZjHza33U07hl66qo7M";
+ sout << "iHWjOPzrMEhad9fsvLGQkA3WNjj4fjx5TLN0mfieIPgAjrQvZhCO9DspEWW+jwRP63BYUU3rB2sV";
+ sout << "oEJfsyRSoam9ujGE2LF6ePYZhOOs41OHGsbUweduJ47XGdt8Z8+wxnZ0ykwvxc4eVsNbNERVJ0pz";
+ sout << "5hULsfB5BCs0jc2cz6N+1MLS397qKGNwnim8OBuU90wU0vMy+QWF78OnVb9jlg3asOK5riTvCWMb";
+ sout << "qgj1qPo0GfWRojb6L2JaKiQlU7r5LiJSmmCQLdy7qnbtc2ul9kKn7iQZqxZVlHJklsrsOCdA3/Lb";
+ sout << "kzpWUbCp21oyQKgp8PRkMv4NhWt8JkushMklTjuvDhvqVTqrzFQE/UJoxWEBEjeZWRgTG9gYISJz";
+ sout << "9mnT+89BXF+oSahu0YO8TKgNMqIDQ0d5GVrc/lakm/jQpZ3nl2tVbN5vLMtCuwbkeYRiFuaQKt8n";
+ sout << "+0HpFoECCJZdk6vyVFpIHNPSP7bfnsrZJHRiprvhz41LowOajR20mGW/+mlqo5K5eVxrW4I2Uumc";
+ sout << "Xxp+DK5yhhIdYxY1SkRYi4CynSNUPLqoD3RaTFKfo+aGwd+N1abtMJpWmE/Xp5k3NNHXWi95ltoF";
+ sout << "tU4BxGQWWDjG3UB9t6eUDoV/WXwCy5pxs4rbXLb2O9CM2HaBC+lDaW9RjxpOjI1jvAXmcQrs/MeT";
+ sout << "ex8n5RxFcyRzjbaWhd/V4vZ5+qY6eLoT/cUpYVOp0w3lQEBaGz0W8bcetjroDYGSV1U+3nBgcKPb";
+ sout << "rW1wp9l+x/ihlfM4yHdApD1WUTYfdIgnO6YAw3tlm0UxARb3WxyVjIQ7JMr1Xgle4UbFSWrjI8pD";
+ sout << "U3arZPJzf7oN1eFDdS/V4fZ7I/B+j580QOmGI5LGvSBVR3Ic2iVSbZuk2mjWgK/YW4vg3kp7LjZe";
+ sout << "yIxulHxWGysi//Oe7bqcJsM8Jndw3sId9UYV9r9GaBGBf+E2YWibCRJCiDjzO4PizCVOnTGJlOMI";
+ sout << "Y7BvFi0d0eLHGAfIm+3d1bUqD1XcPblx0IYVa5AHY90JfMS7gBJHmJiY9Gv9+WtQmLZmNkU6Tcy6";
+ sout << "yNyIMaIfI3UO03ApmhM9babcNpX8xhxYotZXzuxf19nnSdyOebzl40qU4BPzwwQmQMISK35A80xS";
+ sout << "dvnVDMbcRQIC4fjwo/OKNWtk2oLY9ERJ6ixMMxG532tF12jN4ZbWn1X1HGFNXvSU2bFhuOLMSgDC";
+ sout << "1poVi4Cjjgd4n49BJmlkeBoL88z83sPikchLnW1kxHubG/0VBwyHYBmocPrK46PL1rx1+dSwc+Da";
+ sout << "3E+edMWBVe/ca2Z2lBDFIvo29fjwwumf5Ljg/M2YybU9jZC4vLR9VcdPJ9J/gi53iNOktmDcBcp8";
+ sout << "ThCOSXuaDyKBtQ6nvd3AUGdNdLADPuNXTRNybM+Lqc4k7cApgM6DZV3Elpz38473d3HDAW4pCOD3";
+ sout << "K/y2pYyog+/27OSOW9SGoVkOuqOBKwqrFAuD1jIbI/yDq/LYajcJIPqhkUv3srTxHkPiOBbFy4pI";
+ sout << "6NAftTHf4GGy8VTGIzeD+z7L1qJToCogS+FoBG8ixRGUYKvUYEQyc1EhXdoPOYY6pZiMsA4xSGyN";
+ sout << "aU9RrfweZH3ld9QU9Y2kjSqVOhQavzIPtD2wQBIDWxk3/bmH1m76qrcEfY9WKCb7Sl//1oILVf/N";
+ sout << "b0/TZEqVSAFOMoTzTXO1ClXymBTA9b1bJKlQL/8DRayUN0NUMllrwHT1PGOmpoJ+AyhUOjEmWREv";
+ sout << "mKkaxiRkpyLdgKyphJhtYGid41FAAKacNN4CMl9W+fZnydgR0SDvYvpOwveSXr66xfDZlQti8ZR5";
+ sout << "i8Il6sq3+2ybJj/oakohjWPxMAA2rEvsOYkuUbviTAYQOM3jMXAVPIkgAYgwwXhvTpHjeRurdxho";
+ sout << "5dz5zGTwSRsxCUn6QSTtt4DhroBs4xBCmYa8BFsUAzG9nG+SP+ejIgc6HsrLCxZ9Orlgn5nkX26K";
+ sout << "bI2dWHqUL8DIgM9OjrXeWath283tUxYQlnQ8XJ2/IsmRkbq7eNJfBATvOmvk6CTJJdGrK3iX/xaI";
+ sout << "WTJ8J4qY19ehkQoD8fLA0W9FitmfQyLGzxFSI4b3YOcl5KQUvSDjPpG053Ok4LhcQCILRhoHk5jl";
+ sout << "usMw7nWyw97HV8XHrQkjsGyvkT0G0LyeNV5iYo6o8yFtF/s44/mfI3sh+b5AzhdYOEyRcnPSlr7y";
+ sout << "axPlZnAfZRfqccQnEricrTtaPvYaJIh/dbtnlM5crcub0tJ5WNWAlLdS6IShjiIivEzqakfqg1GD";
+ sout << "w4TzFl4VeqaTR7JWeGT+yyRwTfqkIEFWp4/7DyRSXF1hbiUifVaBwy4mpar2tHuSL/eknEI2Hd9A";
+ sout << "oIFg0F1y0Jg4uAewz1MvmFsfoHpVAT8ejEF5OdFjkeUL8fjSBlX2SwMNaV07UlWkDDGckuHch6r0";
+ sout << "FIDtx71pldsL2ALaQgKk+85QC8YqJdzgtfK/lRT0MDYOh4NlCZoFqQAImSYqasRtsyeNYWVi7Hh5";
+ sout << "HUcaH4dpUrWFu8HFXN20rzWwkplYAGTeG1/S6T/sBXzAcv78VXwd8ec3+Soa/ZZNXY+yWuHziyrP";
+ sout << "K7FFd/fcYHML+2bB+E2Trm4MVpzv7n0a+Kuh9sy0SVe0IuVJMo68R2Ftl7tGgF+dTKVKmEHLHqcR";
+ sout << "fSjxUAto2wxtM3Lormd/1Yz3loH8CL83JrK1f699TQTZee6voQPJvlvKJlctr3NeWB0uwk3TIACf";
+ sout << "198pytEpHGhlLByCzpwV68aPjs9EV5yekrCJzEp0arZSIzfI/cgwYAZ35Ukff/bp6jxg6AB6yUL8";
+ sout << "Muq0rqGDqwpfTfTDaeBJAhwevEMyapDwrbzwHhnJLi7ZT5l67Q6Xjo/A8/U60t9m2Sdm5ULwzBdo";
+ sout << "KdSBd9S1UUueBxrx109Yh1gjvbk6k6d8L/Tuqjue77ZCUV5mOJ/rmuTi6OEDIKdzZuBgooisaIg+";
+ sout << "CargeAu0U/JS54e+b+Emr/56cogvgeJo2QeIKT5yhqHxtoEvHjhA+7q8MGuosAeQtp/9yYt5kPiM";
+ sout << "j0d5GjKTviHQqgISzuskcAWAhjIfXSyVrFhiL2tZ9hqS0u3juXdBoUy3nXcx9WF1tLkyxONcILs9";
+ sout << "+dOGRg+VpsTcjRqQyJoKm6OzVoN5J8iWKFkdZGLm0IM+p7F+jRasFIgJd4iPjHMsxYBlFX/aNcxT";
+ sout << "dt1W97L7uw42LMYVG+w3wnHdkO/ddrsp8DemUQzsT7yGDOhg5LMBqK+Lh1tcizQrb73NDpqjGmeh";
+ sout << "wmSb9GCzxDxw9uxfaZBBbO7M4KXJiANLFF86djhSpYgmApyhO1QcTSl2UR4XptqikYbPGFFQzKIC";
+ sout << "qjvmsXWnECWWSZK6pnNnHWZOMto8VUmPx64HIPe1hW7KeRM4ra7J5Imw6F5APG4+Jg8IUf/sH86g";
+ sout << "v3F35nnPnYeVvkQuYP3iLNapQqaKR+pQizKxXj/wgPagwSRrzlSDbKM7KqwbvdBGVMGfeW4PTpuP";
+ sout << "FxtmMKzWMWAGUtPSBHktXyt2yn/Gp7HVfirM1FYaIOsWvNPtBfsQ7HGA3dvKbP9f6ZvRSonW/+kU";
+ sout << "S+jp/UP+sIfihswVxrP8TO0YqQCwz6+X3nCT1pW7sAJKggb+DZyEisyl0jwK8fVttFraIdhqO2Ko";
+ sout << "o2Mfc8+V5jVTIC/VPtuiK0Wjv0+Eov2U1UgvFM0jsGIPfVZV5UDra0rWjp/vnzo5C9MBy/MxfCyZ";
+ sout << "5tC8AnEXpI6V5JSHSb8xRAHWZg4HUMmoZG9u4mX+fW9Lc1OET8xVMzfN68kndi25/bnfx6SpR6f1";
+ sout << "30Nhy8rd93qy7DpYUHhLLyhBgujuJiT4scogc2iDNwP/Fsam9RR/EeVjKv8gwDHrDSbbUbRbzfUD";
+ sout << "fM7oph68ce4/sQ0rCh1WbtPrSQWbNU225oOYZr1lgrfxlYnI6ROd1M8nWS623ofggs4Wfh5CMYXJ";
+ sout << "OYe0XlSNliVnU1CX4MXuX8dIXaEmU2HUjfKWif6YAQY9eSLikPWVgEYvpthn6dur/TP1jC+W3a/Q";
+ sout << "vigZwfynqIl/NC8Pe7tpm2qe/K6TcOgru5ojdaPeyLUsVx/wqvvVlT8ZOgVV2vKOXAUQ8bLXAH6N";
+ sout << "kccB9Aw6NLtXi63VjdwUrgfBwT3orFckTuYA4u60vxs6e2ocbkJa8YsPyN71Q13O7t5q7aYP3O4H";
+ sout << "JbDKncX6fZddc26LFxgRQem44nxcab0yoiP6H3cp8mHB86+vkBuSQHWGSWN5uNK03BP0rlUntMT8";
+ sout << "zis2iDvOY2gDKYHPj57HszSQ8/SZx7MFKiFRTIKMK5P39lNz0ylKhskAfZ4KDzLp6xzwjwxDsy70";
+ sout << "LQatqB5ojtaMcglatNYvdU48iHz7T/KPIU7fs/vySYdx4EHZ+Oei/dKFvpdK+y9lFyRJUoBXpb/L";
+ sout << "LCs202cmGv01lonaN1Qe0QEL8OTPqvPwGb/rqsf6CNobSZd7mmiMwlQ4dARKyk3PWgYvalT7nm7w";
+ sout << "aZvPlDUnws05FXtATiepdeNlffsCK+G/TEzH4vxOzbFsNwhwqL2tVf0t+1UJwD+NQaF4p0mSoA8B";
+ sout << "TZCslymygnhgF9Tu0jHPigJ99Nj36RhdYkndHiry2OlwpTACuBv2CFv9F8SDhfwuRw4sr3xQpomb";
+ sout << "vpTNyGrXXmSVrsTnGP506nCBg4IQOi5zXA6MgVNXiy62mh6u0lceyZXfbvCKkGJi6wUj05DdrCvY";
+ sout << "3TrTH7DxcwTZ01O1e2A+6A4v7u5/GyN2vEQb/p+lSZ9XAWYLywIId2pFMJ6nDuD4HKuoVljrA4+A";
+ sout << "wrwACO6QAn0H15I4nIBRzxgEhL+/U9Cmhmudtl5iKeZCifsTrIda80CJ9rTl/w6knmll4/9rLceK";
+ sout << "QmMKBXjd4sdpcDh8YNAUa4lWNsgL7ElkbTzmZlPe9ScYHAfcJGEtwrOuYDp5LfJOh76nM/LbGAkF";
+ sout << "qR596/Sqf23C+pfe4JH2lerREvbvkx+N9b6lRHEEU6tN5qx4AVPUlVDi2/1qo4wcIFJEKYS4bfKc";
+ sout << "jZdriM9msBQPzO1GDoVTfUxcY7vVtkVSjVONgpjlM4Bsr8YdqtRH7xAEuMFG5y97X5PK6KkIAqAc";
+ sout << "fXc8BSroGGBcXmIx5dAh/U6oQAu8gOe8mSvy84/dz2sFbioZSlVWR8asbFLDjrfHHpo4d4EX3t1D";
+ sout << "XsGHOG0QPuj5/lH2QZerKkfyMZiD7rSJTnpf8oUyY+gw/e0aZMHk510G4ybRKgY+9tCGnu/A3cJc";
+ sout << "5wi4HcD1PUKmZwKZI2PIfoIv/VUYQSZt7U26rf0wUZEMcuUldIxiU583HZ58fUGjmNhi5uWdDeIF";
+ sout << "pgIvY8tvmwUNT3W7H3iw+idsfn1w1CjWmWiCRo+yjAB+TiOxHD4JCCNAcM5PCWDa/NXLBA2tO1h9";
+ sout << "Tk8h96lBlAtu4IQVJaB6+o7iPk2GNq6FAiFQwYC2F/Oh5A3wKWrd2kqQ8JeZtNdk4L2+eHg3aDAU";
+ sout << "4aXaYzfxDSOYHVHLgDj4VY6ulSZx9DBst5UPsHbaLaANf98uIZuji2hXOcg/FEnchb7A5bb+UIyV";
+ sout << "jJH9d2D4R80e5GwPF/vVZK2GQr7h/pEgdGTh6hr8piMsR5fzJpEI9dS2jTJnet4FtnhDo90fImU7";
+ sout << "O07J4AT+uO6k0B+lKuc5QlmaXg5Hm3hCqq5CggvnHNKWHV4f1ux0GNn19RiXwX18EdkxSEDIX1W9";
+ sout << "CmdCn7gQtqznt3pNq3apLeITu3phYapWi3FlHhxoxOE8gKjF204FYOBeKztMqCqSlYa3ALQiac1W";
+ sout << "bk5HyFaFvWEG5Rb2gs7bHSgHuDFlJwErbiDfHM8415fDkbWAOMJFTDh3YY/tuNz4vU4bNC7TcJHn";
+ sout << "o5gak21470Iy5oZ9WHOgQm07tsFNxyJg/98rl1fQ0lcjNF+2nrhj8O3bXRpgt0eh9AQeu6QVTC9A";
+ sout << "d7DzZeQ7N3HCWJl+VbwFCW8Jyo5umAkO5qFn+c15SO7QZ0KEjEORTiUnBDXzAtQjDHURr4yEjtiS";
+ sout << "LkLTQsXwiwCmBOnoTdEPegCHIEeVSIye1t0x+dR2DeqK3WA/hB8mFawdIlhtmdEOZXov1mutXVDB";
+ sout << "LBN80uBR/EypdQyctL5IR7IZIS8p1vG9kY2yceXlszfRZ/t1H3jx3sRSJEdVoMOP6Es4IpKj5uw4";
+ sout << "agZ/POEGbn9qKdL1N2MM0R3y6D6YjIXhQF6QO3XsYlzU/OeOWxoemfC3/qn4yxwbaYyEWjICn/9d";
+ sout << "e+z3q8F3Kh2JC5VsuIVaKZ7MqXxvtn9SBuUQ2vsx/VqH/LyRi9glQZom7H7XYefzQ6neF1DobC/p";
+ sout << "HsFSf3Q8QV215kXq7lm0FUxQHcA2p4F037be3CN4V8aa4NqL/ChPqdR/EMtB4C72nOJClAGY0BsL";
+ sout << "4ApuEZj/SfshLKcnMdTcJTsqBDrm2ykdu8JEg5PQT3vpG72eUbAm3Mbm3CYImISFQiZ07XYDnN6J";
+ sout << "DUOjaiwfjJ4ydnkaAQbDnChIS6JXZV1LEMS19DCB0TLoRl6jnX3mNu4S+fugfFHqXYxgKIAen83P";
+ sout << "YdaCotX2Q4qj7YjNhknIksW1OPA+8VxgBhrO/xBocrJY+uEi4+iVFJE/8Ge8sXmYr4AcY8q6/CuF";
+ sout << "jYWYkmj8UZp69kE9QGJdiwmHBFOLIgAdnKMXuRS2NFZgFcoGMWMxeasH12WFGRmtuoS+eBi7RzUn";
+ sout << "CC7RpHf++XNJClYpMSPnEYafiDQOcMmjHcaBYkEBB6kRV6dPtwrb0ZQPGVFYnhhcOtcM8tkLD0k6";
+ sout << "Ek1+UYaG75go18OFlshMOzU3Rq7SuuNwtSNQ6drsWWcGYEOWtQG1b6DniQ4+e9hkP1sHI9GE3jMV";
+ sout << "tbuSi8Q7pRY+vzyHyNIOH5FmnWCFPYLMkHt+6aenSR4bh9b8Bx7khop+XymNuNOZg/hu863yOx7P";
+ sout << "D/OCXH8BflcACMxVMFKcPMxYZHrxC4cINAO2wY7ooge06LSlM/3gNNwfizSn5miDw+3d4UsnnD6G";
+ sout << "+oMA9AJTuPcy0tMqBsGqmBZMAIO3yHWroF9G0dS2TVJqMn8Yt5shS7TKoVn2ognWInejfbOSP8nl";
+ sout << "wliaBSd4XCMRoacNMgoPilfwQsqwntNn1jsNRVG3YwQwJnSWXo0YUvbCeijqzP0pX7IezmCY8qgI";
+ sout << "VG7spKv3J900W4CCvbAlNsfHnNAnjU/5MWjs7I2j+WhuFv+b++3vDsedHI5nUWjTUYYy7N8O48LX";
+ sout << "XH042vXLucXjT4inm+IWDpj+br+GmppCY/bZzqO/IwzMt8pWiReyU9NNtawN8ag6FYA9fxrqGwCf";
+ sout << "j98DdzKzgBgo28R8Y2Al0oC52pFovY0Ym/ormPTSwtehSaq3lTFgbCKBhYR9QPfx3vMbYZupWWCD";
+ sout << "FjnZYkKtJltasN+SKs7Wp/cCU+U+6zPAqHmv+ZSWiNhC4lPgYDGSdyhPhp/sHz9rW582bdo0iUT0";
+ sout << "8QRPz1UGheorTDK0K+V0sR6ltaIS4/5P7/QzmVvGnnilWTFmqdBViBZRFv+3wp5xMqMjtZthbZtI";
+ sout << "3YmEvxUwnPvJCu3+veeErSbvB9AKDj0PJGmqLx8Cw+SbQgN874XSSq+w4WVXCT+GOUrspzZR1LNi";
+ sout << "59SSCEs6AKkKmXmjk7sdl6FocyINLIGBUSPc+nwCgESD4xSaR1cx2SjSf0CynPF/YprCxvqRvQEZ";
+ sout << "dcKWvwgeU6oJP/0tz55yIZjiIi47ucY4ySXSel5iPoofoh4Gg21tguOQovIAbzqYrkN44bmBy+2S";
+ sout << "Bpxa7JRdQr+QXwMMEbsnjrXbdHL7J5fZa/80FkwOHY8Fvz1wCRoZ5y0EyAZCq1s5H4Vd4yHMaZmW";
+ sout << "ZNJzXvADrDSO7NxyTDGo4pVX4Dxh/v854SiHkO12eDvoizsraCz2ENtE6cbpHIdRq0Tt/K1HEH1E";
+ sout << "V9l7eNcD6XJrvSe+6yBEJKD7srWbyC3MPSzfl7cFEZPbVzfkjSP8H7AnZl9mFnEv8AbuLvHJTVzq";
+ sout << "LdwmDV35e4jFpDbf61+kzeO0F9ABrphKOY2YP01f0sKoIicMWOcXyBVIMCtB/9Bav/Pn6bH0pyn9";
+ sout << "fyVa22J4yLzvKdYKluBaKUYVVUS5GnvTT1Qxdtlv0AWceJApOg4sHx9zZmoUMDlQQqH54S9sikKk";
+ sout << "NnW4TD+CbdPYFH7kgXAkoFveAOIKcZZhTUD3FLbarLFqwcU37NSuqM841MlPW4Koa5Jrc5ySoL2U";
+ sout << "FU/Xu07j/PvrpxdVHbok0aRtPgNm44+vPDAWmuG8zuxqluSW2xxzPi/YVo7nsWPvJoDKjZA1aRMr";
+ sout << "LehSLFoQa66fCq39/XXbQp83pL9b3tFGRndFnP8FxvMcCaYkG/SDevUg+cG1ysNbBSBJ1plCJe4S";
+ sout << "loGs/jQUQCNIX2/mR9L9PHM7FS+KfQn0tHgjipj5DRGiFInscy8cXn/44uYSHLvZUTvdcg3+I9hi";
+ sout << "qdV0luQoUCZm9ooT/SBeEo4VzB6+L+fsuOlYCQloHNtmJ3KrHtRtbk3caJcrbTcoQETMbSGN5awK";
+ sout << "XueIC5Ar7zL30I4/DTjrhho+/6Kf4nRhplqPpt+0lyLOSk9KjeNxWktMwnnplhggnxLqb9laXNAM";
+ sout << "juhmMFkTHN21kH6F3TDmBE6rl8iMHHn1+kSKhhYjDeb+n35qu3kYYEg651ow0NVdq+aPC4YYCvt8";
+ sout << "44xqYd6LxPeXF66jNdNl+oOBdds5MLOyW8uIFdQbmh514Q41qZ3TEMieqT08Rp7qW4/mqiPjRzp8";
+ sout << "DZgOaUXJnQnUKkVbqqaiBv+ot+ArYe5JB+e7nvzgyf2zxCZLk9/Szpqn+JbGGEHFixV99XjJQRTU";
+ sout << "q5DcOkzNjd2/Da4VEXCfjQPWgYlYu1u4hSgasO4GVpGFnyuj76gnzPGbkSVq5GMJ4KzYtl7/sta6";
+ sout << "sijpcScgVlvvL6ff7fhEVnwQfa4mCZn9/umsDB5ZbG+VJufprMVSb5CMYcMyOU2KYDyvWHE6jSP3";
+ sout << "Za1W9Fjo1Fkzx99+pV5Hex/GeiEOxyYCPjNEvCNpn9xJWjU8fx6/6BbN2mGET9hO18lol0OFeBio";
+ sout << "88h5F6msca4plFbxu7eLv1Mx4kyQNmvupkPaufis95NgiPhNwOUSPsGffK8WGIaJJx7+g/SkgN1h";
+ sout << "RqaZGgxZdrnY9nOOB4TsqNd1dG4p8ybarjysGHg0JQEFRcxj22DlC2PoAMEEILAjYb3cIX0xxy18";
+ sout << "D6TPca+XaHi6LoYixk1zz+S8FdUGweRHS43IaWzBa9KDJ5vEIxAAXpyJ5Uv5PRcBhAfdjqjeT8DN";
+ sout << "bVN0R0D5QQA=";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin, sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin, sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'frame_000102.bmp'
+ static const std::string get_decoded_string_frame_000102()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file '..\..\examples\video_frames\frame_000102.bmp' we want to decode and return.
+ sout << "Qld+lmlZhXVX5NDRWIFG1T4+OGdJbkmxAXXdHZEtpDf6knVTlRWyAhgv85Tf11KJZbhKv1dcsKtQ";
+ sout << "fX3y/9RxoGwtXxwFXCxbBrLRaklamboDoK5N06vzzd+CS5m2gEc6/c0nITY0hfeRURvJI6cvb8OM";
+ sout << "W3UbsFYtU1ntq1umGkQDDu2ukl7sV9LfHj5eh+n3zjy7VIX/RAghwQA44rcpnh2d9icwDh3G2dCo";
+ sout << "KxHo3W4qqxVLis7IIGg0dzwguoB8ZGmlvOg7hdMz20beAel/LlU8TMghQk2Aj+4NTKQRVwcfXfdd";
+ sout << "AyOhcT9wYaLabnDZgL+7yq8Ji3VHvlGqgVD14WJj87s83dgMGikK03QgTzhyY4dwADT1aQ+xqeec";
+ sout << "K5d37u4xE+btNpcqFhHx1YCp1r6+O9kjWRE08rfb1qWZB4qyCwTkxc1C5buXaeNRrw6pHHqSLWd0";
+ sout << "9IFAbB0ukrEWmdHr8lVKAfBzL+fTFrAO8gjgT/vf15asPfqSIl+zJyHK+YJ1p0F/UwIzPkKl5nx2";
+ sout << "O3u06yBtIHKdflKGjRSXomDYGjrjeoLNjqF//7zBBXyNXXv9TsWwekzsX7A+qRdm/j/C0lCHU+sL";
+ sout << "g6wWh7L0kL4ARqClFQfanO+87/EPhnu9LuovQzTY8PhLB7a0R2fhAncpTEPCHBm/0bTEL5F7V+W3";
+ sout << "8yzUfcgi1NOCAUBN1tVwWBDsVv/NUIl1x+FTKd1BFAsN7a0LLZO3IGnCikPyU/Tn+TCslyvvnU7C";
+ sout << "SxgTwVZIeDC4sq0l7kk3Jc3UWrDI77EQHjxNFKG+lnJxMLXrNMy/lJ621WGz8uVPvpkcTajH/YdN";
+ sout << "eaRRgbdqnkqmoSyX7cJeaZG4NE0n+isv3j7WU3cM6N8WKhYCH0ReG7XjbdBgrPHaUdFD1dV20eC1";
+ sout << "2PSv5D2jEJkDUVNdMZSmwOtF/UDg4WRMY80YLGSKhxqLqoszhKWXltFdm1M2+WPtSFOdr4i3wZRs";
+ sout << "W1At1+bmMTFCM18KnBg0mQv6zyjKRjzBPHLiQZQVBmv3al6bQnyLsbpNDM79oVd4cdEv+l6Cze9Q";
+ sout << "gPwotlVgN8hi9gcF3lH+KTQ3Nmd7WK3+125inZjFasNLUVJZNLshz0DVnKWeaO4RGLx/Nb2ceMwG";
+ sout << "YknvrhsARhzLZe8ZFcdvQs8JnlXwuNpN9OKtBNQMpQHf6ytCWCV/ZCsrFCT+GnKMQxCvR4/LNIFU";
+ sout << "vWKvSIe1iIDoOhUCgJknwUH1M1Ug/VLDpOxT4ylapmV+YoKSYnJANOQ3+3FhqHRc2KG8vGMTNzab";
+ sout << "3rs5TEQVOdP+fEtU8oynfcb/0WK1BAKgmDRhKcz8XG28EX15aWyr6uJkAxqYE8UXHOr+kn27TuWA";
+ sout << "49KqCFNsNcjhvnjWQEBvwTwGRKofE4ASdnQi/fF6Ozk321H0GJYpXETW69XJiNzT0f6lDUYWR+Bd";
+ sout << "HC1sW256R9dn/MBAcSH2FRUf0Mv7z0yhkb4aUwHNvGhHPX5g0Bhy6x1TCOqHtjubkHkxcq6YpwW0";
+ sout << "f+9DXG2M/sK+IPqqgy4tY/fcJeYxq3Vd4+voDPYfVxcWpmy/4X5kzf+fFwtXEu2MBdYKQEKviV0Y";
+ sout << "WixgGguhWig6d2vAbUKgAlJd9yixtBum62nEK1vMZmwzfokP80fimNdw7Wony6EA+v1oB+zHQojG";
+ sout << "1fNaBTacRa+NsW58U848DFrsJ94S/9ss/RUx8GuaWwKP6WImvkhyHP+YdbtkykVPVzm3s798VWAX";
+ sout << "nvjz9R2NlupUdBVgJg03BAH4DoJdYWOxnLtUChjW++StA7OGgWoay7DDs/6AJYycFh+TFW8D/HhA";
+ sout << "sEQCUAYDnpze0aSX6CBZ7vHMr4z9Gr6V1zE4dbJ27Yv7ZFBetDLTN3MN1vk8SYDFeFHtzyMBfqor";
+ sout << "hHXu4rKtGW2j084a3BQvlDVZ5bQX8mh6QBENJ+C3kBUhE4QthRIUwGsuarKCnOUAAL2Zt64CgGKi";
+ sout << "gRF4wZ3V3Tt/FZ725pUJe2Td65CddbBd2mRqEzdN+qqn24au9ucznuEr7E2j0T3ey1RWEcU7Xsx9";
+ sout << "dEX6LoyFqowIEvyGOwdTlycOq4v53Z2cJTaitjGSvtaL1h1ASDW11jvsX0OHueMJJyLFwKOjj5JL";
+ sout << "JrtfkGvWRrycw3UdT6g2n8IPKk8j96hds+UlDvgwIzmlromWvPfwixA9mt8MRqJlBIo94lKjOvuw";
+ sout << "sS5FUcr31Dqmaz7uQcrwmxh35jAvW3EbMObKNdbaojaZl3u2Szt4LA0yFs7UJpkkJgEO9E7lGte3";
+ sout << "WAUC09lpDNq1CLvEfOEsWQqzXayT9AU86CCnFgi6iErKoA3uNToSaqQVOxOi8RWzQWuNfmkluBMF";
+ sout << "6NmgipWLj1nlLLBUOpQD6nVlwYqZEeiaQOhHRYUiSUFbJ1EVdBPoRi9CPOquM1WX5H9qbUOBchB1";
+ sout << "/oI2wsh86ZqOld75VfD5QsHXmrFsQ74mO4MyvAojodFWADFmRloe6UoEBFYhjXSlj2sUSTyAMfPh";
+ sout << "jgRrJwdMb0/53hm/Emqz9AhG9FpTI5P6doDAm19dGp09NvQyYoZnCCWHC6fPpl+BS9WANNfsSZnl";
+ sout << "dtI/JmBbtlx51QDTA+Dc/RqGZZFzIIDnBoIUnyFY6FBb/S03rQadSUdeuBInghBu3bw1UH0AImFZ";
+ sout << "uy0gKklA51AkE3xVxtyGaCniGugrWwcGYl+FeiisBNKtZtbo3spTO/Rr2Fjg/mbJ1I0dCDf2gJt5";
+ sout << "qkjF7zRl35+gl58FjkBxMdzM64289w8wqjKO6P1JBnJV2gsbU6QYGN/w3Xy9BC6Yq7WaHU2eUves";
+ sout << "tyuWAxa2+pl8SzrrvubhGUV0Rx4wVcRCLilUKHQ9VoCEJeou1y15h/hl8BkmuU65Do4a5txsH+Xt";
+ sout << "5zVkkmGnvrvq8xMd15UIz867U7lt+BwgV8UoDz5ZQnQXvwt4+NLK8dLaRfr3Tb7KpLPOdymoOW1H";
+ sout << "7ZnfmR75beprkaMn29qygGhlTmVTxNC7CppNNfS97Yc3ki+g14rkFZMmIpETfUnM1eqp9O1+y5Lt";
+ sout << "1p1DrkrZduSwZtg4DmJt/2g0eV5xO7LPishn8ezxLTcMLCQYZDM4gjhiWt26U0XEQClxxouxQKiV";
+ sout << "jpcwn99nBEj5r7tkQLfJ4clQW8gOuBidgJ3gWiAlR/Pwkys4L7cdQybo8WegBvXRJyNi0mDGsM4k";
+ sout << "cD8A38+zxN/mI7Z1Gv7y5zWUMrILQJvPVXCCWXo6gikdJpkLrprcp0RUXo0b1iUgGgOXVvY6PGA9";
+ sout << "HrM5/u0t40+Yh7+3XqzLWWU9kuOgDLvjwYeuRu7oniMmTWOuRtkWyqKmTXlrwjBz+yqIQJyiAa0h";
+ sout << "NF+n6CNX4Bk1X2h7DIbZf/hCbYAsEQ/zHAudSiEfzew7T8r/h4YG2huCTjV6NrBNOzxk2Bu2A2kd";
+ sout << "PbIOFbLWphpDX3pQtfSvx46IL0uX4O03VgTiz2NCvNKaH6oZZ8mTxkV7QmVnRdHG2my+oFsqtkv0";
+ sout << "uRF3h9xXKDij2r3lfNRhHrM3OAsySepTuXa0hN2bU0DIiX+BlxVjBKicOLIQUI2k9ws3akGMpicU";
+ sout << "vO/fKIwOs7D5L2oUOqDcycceYM3DCTjyjdeP9hq9+w3nxnuvtoNuFnE67nR0FA/XSYLjZOxq5EYD";
+ sout << "N4LdNhDWzYFjEHXgmyvc6IrCcltsisuRN1GNZmXDTd++/8CdA9ThbqH/AZvMeUt3zZeKMmb4Ad3o";
+ sout << "T9in73sligZv9ed32/6rc3w96aoiGtHgv5szIJ+h49hCNfuVoSR6GB89zKr3cHcsQ1PyI9+S7ON/";
+ sout << "/lTAQtwIUSGSQxM7xmawtKVSit1zv/gw307SfoWAZMmz3TzrMzKbe3mmNNwW91a6GLqe1iyaQ9Lf";
+ sout << "KdIVsCHzqq3DKgex8X0XPnP699SlqSR9gjHWZvuVOzZkA5WE8oatWQNS/W/bhBaaAiT5/781O1s2";
+ sout << "9y+RfF/lQh6tQbhPthbY/ALQDR07LM43qqvdaiinxT1gYh3pJJHs6oEQEAZwNvbjUZURmwbJ+hE7";
+ sout << "fJnWbYtftZn7pxlJXzXueWe7IPmYuzrn6jJEh4xbnANe2gpzkGPi2mHIlJ8ij9vp5KwkaZ+SkmEB";
+ sout << "El1hUdhsJoXXErzKm76RD0oLriVUGd2yvI/pM5Mm/3/pykt8cARjatq2CVc2YE8P2M0cC3ItKD0Z";
+ sout << "YqnMdxmJpxys5JoN7q9yemZFpiV2OMJ24kPc8BGJtgbVQBWpMUnNEOZOI0P17D3QRehHWf543/X5";
+ sout << "PqzfHj9J1tUcJMNCpp3GFxejtpOvKD8J7JB7+0QzqCCOE8SQIC3Bs6IB3IeZiYj70f3XU1UPF028";
+ sout << "Kbkis0YuvkL79pWPoqNAoA7YVVGhnb7ed4p2/lqFw1NHG0+H4YQO1gz8U6MeiUrjcxA/IkwNFAZX";
+ sout << "5WsC2QSadmv7OtUT6L9ifTCs0sogqcC5UETke+cLIfprQ/c4qIMP6JWMqRasR4+0qjxZbSxovEme";
+ sout << "0oIBoRGE2za5L0/Ulwcx4URU5/iUu9u7IPEcUVQzABaMIN4wMA4Lbd2evs1Xjo6xcFLK/DBtOUdM";
+ sout << "JTmiOUwloSGDd8MSx25d3BM1HdXfUc5uYihDFkk/0AUSLa3x0GbKimowJYGAkr6Px/5MsCnFW+Ix";
+ sout << "anv9LFErILEMTwCvETg2LuRDSC/2uyGNnndivYpOu8QGplJbW9n4ALWpvS/dc6PJKjZo6GhqqK/X";
+ sout << "U8Q39jn5hSYIGb/LXS0mMJZ7CPTO1AcNCAZb2r7Fc3orKeMoBDA+9R2x+ZQnlGWV8PdAzfpnfsIa";
+ sout << "O+JL5Nh2NimtPQsqEVykbF1RF3caiYPCcEj+SAUFSDZ2pe+YfXPOpe2EOZ/BnGTQWdn8u87mw68G";
+ sout << "Y2zcXQAjUHXuu8iF3IXR0bbRR4bDKp1MJ3YW3nlk2E37v0SEkyX7EpXg8hvNB0uReBLOk8pxw4Ha";
+ sout << "8R6ekjMAfMnOQynT0gi3tOoy6/CNXBQFAp7/u+Owz+DO+pRX9StkBjFUWe6+8ZeG9YJLnNJZUGkY";
+ sout << "Ki0EEoWpBbW4zvGa0pOPJ/OceaYIzhL2/1DohO4dO9jJkOU6UxpYaHMOqxr56K7MCpJF6k3ii/q5";
+ sout << "yLDM1Ee3peTb6MfWrrkeYc9PhEtD6TdlJwQpHkivrFvBvp5tz4Tg2zoW4O27SZZn9Hr0MPAKCT9E";
+ sout << "Vouc/LBstfyV8cwXm+nqNGg+f9ZLgns7No8isMXQTPso65SeRw1K48aIwSqeZ/LZ3fQZ+n8l0M0B";
+ sout << "BSRAF11nGpSNKY/G+7vKuJ+FVV1z1MXmc9wp4tjnYRMEBsmhTnL9fFpoHvDlOAgI7ZN+YTKFOP8R";
+ sout << "RzeXkz6ne3/ztgWIS6QZ1xFzl3rEPwvcADeMAT5C/j9COs8YXQUafQ4o2I42PM8PloMpz73nTNqR";
+ sout << "yot/tF65hOa7X6sYFISZxTXvAq1qaV4j/bOyv7Rr4IMQkvPhZRnKuOKd1lEtEleREDKdNA+3Un3u";
+ sout << "3czlYhhMp358CRLKGyMNsLc0oVmrc3Zf7AljUJg3j/WmyZdSWCfCFAUzh4y+OF0r0LSxy566EC0f";
+ sout << "EvoeoqDl6Dn20my8VVm7Ek7kqtjGX8OPXh+OYw7q7GDHCLn+gSQKRPZEMAVwFPfY5J0qUdn2EhBi";
+ sout << "bIdpDLJlX5A9Tuvsfk6/TgWJWrd1ljnk5LRU1JdLpy9Gr3i7RuUzHVmxutyDezdNhJQ2a/dGJoyL";
+ sout << "wqtRLh+sAldKv7SyftQMUr3mVgcuViK24HOW55optbEe8LiDnZVyjx0fWPnvUF3jrOu9iKpCzEQb";
+ sout << "UcV/ItitPx76PWI/HUsXW9nPkyHBkVhy5n4A5OFbK4O7r1eiQBRttalZs9UPIX/zGjhL+mKsmDPZ";
+ sout << "5W1ejsVxJT54FOwFmCD6yxgeWyGirMHJ8iIwL12Vf2WG3NvnLTIMokCOIrJIGl2nsgpYWFh66aLF";
+ sout << "BY52VplzlZ7uvieN8T1gFkoD1GKDTPvxJdbUIyCQG09lZhFsqWDT1h+sZMk2cE4UGFa9SUZY8cC3";
+ sout << "n8nDCxxmmQybJp70Ig8cQPy9US51O+PL8ZjyRJirlSwqhSXndjyvgm4xk9uOSk7AooavjRJYlO7r";
+ sout << "Mm+U11XEN5mZJL10W3nMa3Ls99DQIrifOcWVAaY0pEjmeBWHizxOwwqt3X9CY+Sa/X35awGgaQCe";
+ sout << "CaaIXBkxwkRLD8/Of5fYQ8Dwg+LWZnkMjs1IBdauSjdWvT7B9CXK7O+YJC5kjduIGOAu8qfJqG6o";
+ sout << "HP/uOEvCq4vT6Fg/gLbOjNenVhZSq6bAVSgG3C8/WonUeNQiWnEI0xLm+WOU1L6bcqBNHNBOOiOB";
+ sout << "yn1YojmgQszuBRj2yC4rCAkddymD/yzJ99g8QmhpzlakTRtpjf9LTErhIBDIQSd19U8mNdu1u+cT";
+ sout << "PeIl7vlVmhhnojOHfLGRvD5Zy5dC9XZiXRRcNWHj9vOTdrmtwy0mPIZZMPSBLJnur3djgCLfMniS";
+ sout << "Q8iBSo8Uzf00zSZBUBUmTekAAHFvf+we0/ERcXVkJ2ikfZ0v3sxGf4zIVGAiI0Nx6PZTWgW1xH9a";
+ sout << "3OYLo3mzzz7TVy/Yueh2awJyZ6CWq/ysu9x3tSJG8DbBBc+4segNq+IKeu52mYTcLmASIR9PT12z";
+ sout << "ifAJWWtKNPR4T/FK1pDTkaVkULRPzqHP8jxerpBRMnt6FStshZiZOs+DZVrXJxSP64ZxFthgqMd2";
+ sout << "UvzcqeI8yD8ndIyd69Os5t9OoeWseLPWq95+5OUX5v13wiS+EHbJBNnZLLt4K8udeohSNUXEBDND";
+ sout << "tj7TDkzLyXYpcm3KYkJgtRY88kwidchhjvMQRDNw15ozLnR01t7UsNLVLuBij9sUBDA81i4YXyrr";
+ sout << "5se81KvEZG5kLLkFCUnPKRU/3aRb40F3zvY9pcBU6KeJsjBQzKRX/EqFise10qyClgAyvADqyW8P";
+ sout << "jMDslvAq1mY3kJJU74AQNRuFP0iBJWTX5B3BinqVoE+VJzZPbziFVs0riZccQIoff2DiHS49f06c";
+ sout << "NvWgHb04xNXz1skoINdhFVRSsjik+qmxbFE90F+h9eshTMxwQVobiRLdLv1pGkVOpsRxl0eDsPMI";
+ sout << "NECgDvYSyRtSxXz+SUGk4dokSgkrTPa6NDx82FYiyITDu7wcgtQBOTj+SXRWrrG+KB1MR5cRHWP6";
+ sout << "nmELArZ2JquWF90mbylFHbzKZNB27/TLN3X4/0cVqLNxyzow44+Z8f26lOFFnh9qfzqS874839gB";
+ sout << "IRvAiKnuSo7KCh9BbsvAHk8a23Ei/KNxJFH745cvLab2oVcPuFdwsDvuYgPNT22tuLb+/QN7djB+";
+ sout << "6a84/73zWFCnfeMlPgtGbxUE9yns4nYTNx+jLDUpKAmYBWeiPEiGhsvJYwy/dKvXF+CVdUHFbzJO";
+ sout << "r6rnCYGBY4Urxy+S6KPldLloAnA2SgsqfiU3B59g18OuY2NyPQ2fj5/Ytpum62hQo3SlZTVGXFq7";
+ sout << "pInYYEueHtHIyJA7xpqX7TG8HrdRJRbz0Obs5X0P1vbpELhaaI0vppEIcfzZrmrqQfOT9fUILia4";
+ sout << "DOCR6e6TWVirmzFa8hilcMLjG89m/+h34mO+pwqNsURvWoJ7oixSe9arMPUl2pKyA/wICP8AjQak";
+ sout << "XXaacTp0DMIbcOsf1NY14cuKUgl7tcst714GMXCHfPCnYMUzoawg4o6LVOzHwHRgys0aWz4aNmQq";
+ sout << "5UJDqc1UWVweo8LD1++5BCSMO2pNJaKdbHqVhT9yJP5NxIkV1UxvH1TowNN4SI7q7BMH2fxRBB5e";
+ sout << "bu2XU2s/5Vl7snSkKk0PxmbiiwWGiN1Dx9YIUCEZGJcomUh7phIlPaoT44MEDMT96z7neW110We6";
+ sout << "/FUCAtq2aeF887UH/ARplwM/elwZyI2BIDGAWF5udKyRtCrVznJdXgtlNND4a8MM2OQicC3D85Z4";
+ sout << "suz+m7cwYIW1o0xBcuM2ASLhhAdATCHoyD7A8fIm3dD0vMKM7vA8QQi8ETjiN7GzRqoyHOLt1+4U";
+ sout << "wM/BQdskv+ufGD3KADK5CrKPyKzaosnPyGYyzclqSBbt//QUdYBQO4AP2A3hqh/QySkGID1r4fUC";
+ sout << "cM+fXd4DhwvNjAZHRPfGPD2xPguPOmmuCxkHU1CpcKdBSbxR2q4FTdaQ+1HBbU6KZ6358kqT+5by";
+ sout << "3LP0eS7VemMfP0d9rshtgbK/+nG30EGTtSIJe74inTJ63k3mkHb7jRu0rn+vmO2aO60HQM4SUiK5";
+ sout << "eKZUz9LGB6lD49IqbEwj55SpSUmLsITyO9HdZ2hhAAxRTQeMz2xatUny/fFOGSUiBSeYvyrmnWjs";
+ sout << "R93uXWixgiS7DC15ARLHAkvkhT76lGJkxfdyhdkneQlImBYUecqxHmGRAEOQEUFB7o7ARObjdaFr";
+ sout << "Cii//3Mj+6/YSOAaYlS1YInt2Wo2+gin8+eeqpBp88j4NIH7qyKiGw/fco3w0Yi/x/2tbc+OR79D";
+ sout << "HylA5tAU38lKI9ZuW3/8nYGw1mXE133YDK8ZVzGsU5JnTnCuIW1+aVLf5pzzldfg3z49X2S11QnW";
+ sout << "SNtd3gZ6cY2sWHnQ0gm/EIQCF8696kwZlp/J7fZonWd5Fr3P57QepBjktJs2ReoUXGQGAYABNJAK";
+ sout << "VdbPpCSu/kWlizZFudp+2MxUJnGMg72fGFn2AYhlW47Luuu3/DNQiHhmrxaqXbnpqk+jn52j2rQT";
+ sout << "BRiIujM4aCQk8bXqFCvgD2pcFpKMKtwgkKeLlLMhqX4H4kKZ2h2KpJPSHsTg4EW6p0p1boVMoD8H";
+ sout << "ZFZWTuDKtJOorF/hCTAC7paeeY6EqeEs1S+5ujoI2XjTNcai4TMAOe/pAdgpVIRIybPZP8kWAc44";
+ sout << "P56yfuv2RYxcqAvmpEjvPqhaP0lG+bOUzxAelJy0hu0xe14CdvwWZseSDq+mDaFrrM2fEqGp0eBw";
+ sout << "ysDRYDp0HJaY+QM7mS1chGIw3iTOg5IfI+wgz4BqRz6ILSX1Ci93QzzMsr+t8AqDssxzDX9kMNsW";
+ sout << "oSoRYt29qfxPr7wjBdWURj2KxpW5yCygTMfAh53XuqjyEmuiSu30o3fCOzdQFOppq/LUul6A/Xbj";
+ sout << "anZBHBWlmaIpPtvtdvjcWrflDrwdsJVZENu3qKyEmY+wpE2MMqXUtctJRBr1eauRU/Kcn+3JfSji";
+ sout << "PtgwJ2W6ztTzjqr+6+TRCqJ7xnzIZ2Cj9jxjcD5VCEcqAVg1/rlP50cHMlBrW+UIySQQRG1FtX7k";
+ sout << "8zqh30BJhM6Qff6NrvLkpzAl6qKkgcSe3tsbmovCf5EmB0irBvKg15LiCDxI0HyYT+KfKv5NBgjB";
+ sout << "NQDDNZzqulGPMIqzBGaZc29SfIHaMxYihQS5mONL345HTVNQg7MkcHIYalGwbpIbq3GKv5MumOVj";
+ sout << "SP1kZ2BGFt2U1A0ytDfQLhHan2a7v4+7T5JgUkRrvP8hKHRm0JTMFqFxZpzGOEQ9dwl6atFoNdQw";
+ sout << "f+5ZTWFfzYzWxfvZT0j18yQ4fo8VQzCqlOc5kLYatapswTogEQ1PGd3UH9gTs4SfMjmvrfre/kBL";
+ sout << "nTISbSjaS3Z7N81jEQkExFHqRfxiMIK+h5VRZ/FwviueAATnsIY6vChZYueN9Y8m92Ou81EHj6Je";
+ sout << "o4mKrrtkUETSWP7IkTd4wD/EC7hMWvA7c9cWpY7Q0nAcruSrfcUgks3mW//cNgLmMo0UE4+0W8LM";
+ sout << "H5Ib3drj/Ha1OAZK3NRhtUN2TRgJEaLWrvJ3fo/xDyIdmm/Ap0jf6jXGlXtdWl7KaMElGsmdnFyb";
+ sout << "xgIsGgh9k6hyZ2uTFcTzeRFcsAVOBkQWOBhyqtqh2asmPFjOro/sNvstEVD4+SrHSPG8rlqK3nr6";
+ sout << "SzNq0Is07At+PS14wWqp9ZseQSLr/pWwK7a/CyyAwxnbdJqhhsnxmODTz7nIWFgQittN2Z5l0RhP";
+ sout << "C06ZoojtRQVQPyjCr8C0BnFGyKapnGPGWVbuzlu6xMhqC9C4T+4zjsl/hVT5BaBKvGgjvxUJ9pWi";
+ sout << "fs120RVW4ra/T6X1oAXvYrjp+2i8QVcOPAC/jfE3zT1UpsTrt4IKYR1ILwbWsOi9ORJUqpQgQKpb";
+ sout << "ZrMseH1LAmp1RzFN7M3Xo+wWx1fu9S0W3ZYizaVrkbWrGJyv99zuiCeIY8Ns7oqUfQAfBbJM2TPb";
+ sout << "6jmkCyD1U5a1tir6vGc3YDkBryvw1oXRdeQEuKPSF3YVsp7bHf03ALIn5glbDJwh+8FvJVX0rkPa";
+ sout << "yK4n0dU6mBDfyCt8yZ7/uFqPHVr9Y3d7Ec6RJPEouC3MOlKhYzow/lkVnCVteEaGqhGh42TsKnHt";
+ sout << "I4MUSgA6n2QVTcFfD/hsQdtjzWoFupA0v3PsXobN27vz/aEGrtHjaPXKNDLfbRyW0OQN1Rfj/nRG";
+ sout << "+TbEr9Y17f87ar0qnd0aLd/hgEJ65lW41HWWj3bjRP/RL/X5HpKVzj5zOPBfnOH04vCT2XtjAK2o";
+ sout << "J9gFPdwz+6hWrKXGuQlrIJS+7RpVwZG4woY4cgBv95rFjfWwLrLuuX7PYeCJNLFZKpoAz3WpzRYQ";
+ sout << "PepcF0/AzD6U/dLKAaI3pr/g3kItwzrhGIOz8ZLN4IrVYrSQ+kw+R9NuRWq6Wxg84hoRBWN3hfxt";
+ sout << "A/58J+s/+DnmBilHfrYMhysYMVe0TaN0fM/Am5VIQW+lQJOVY8nVFqxxxt3BTNDAQtVl1BwaRQw1";
+ sout << "7PVWmpFsBKX/cIkJRfuUo47InS4SvzV6JEgNSJb4Jp7BHtNHQpwKDkCjfwcajIrde2nIEXCZ7CPX";
+ sout << "6TmNL3i/ys3IU0zW7v3uDZja60mepUlqvb3mJsiPNu0OkX26rIO+K/E9roqWnwp4HdzTCgv4Lmuz";
+ sout << "5jaVBx3ZVxdjB0Eb3Kkt96pZflyLdI6WSR5RVCfpl8ov/QOKAjZoihm3/YZJJvytsUsj+Wi9CS3G";
+ sout << "If3aps72fkcCfzlzB/2H7HS2Xmfor9P+hBdfEjBiz0oMlkXo0+JuamAk7ueQ5RO7YpnI61Q190x4";
+ sout << "vgeGRm588X3qNb5IXuhumYUZJ1ATmHc9mMkNSNWEGdFy13DJmhHl+fOrADwMAy2+J8g0L2yHloaO";
+ sout << "rSycaN7DgGe0YJD8IUbgS8QMOz8Kq1/Dy2/Uinix2smPobySnP+uQjRJ6ilbHnZCAa5t9KB1fNRs";
+ sout << "HExRV0YMN0tZ/njB/hUsI+N/sg3lvPtSOOpXb8wAQQIcj5v7rCaCBbiGdfjWcgUbHfLDgFLTxq2q";
+ sout << "LND3J3HmONGoE7kwPwNRBMD06KUY9PYwSqjQ7spkdBOYtuBVqCbnnaT6hnh/DsSTqG6DkymArX6G";
+ sout << "Y4SesPr5KhQtUvkrHHQAAmQDWALzA7w0fKLi2unHSsRmteT1ctL4lGwVdEb/YFmNzxiD7BM3Zqvq";
+ sout << "JtEDUScoB94K8R2BBOy/CQqEcln+DCoukLW8BdLAJ6b3mDaw8tLIevYutQwrQln0pc6HwXKmVTeb";
+ sout << "AKKBMmZaAAClk5amuEkyI5YPen9gSZDX45yRohZcef7NSVOmI1ma3mc0rFYJYkJkC7T9bcpcHqAb";
+ sout << "WONeENewbaLz1onBbrVYBdqPeBWjrGt4kOi+YSXtjm6WdZRtLf0cy2uRq1gvzg5oNIDGer12uAAA";
+ sout << "AIqr189l1IrG/3MtrYrKK/Km9wuukr7dJe5Qf/96FXuft+BUsbt8WYQKOxeMZJgWfoZVUzKwkzEN";
+ sout << "/+uWsF3fYne2EclBulQem6566qaX95eQMQv+mzrBVL7+PG6lweDQ6r6ZETzX5ogxLqyeqLSue8qJ";
+ sout << "xmVPMI9fr4rDFcRrt5XgwH2j/QB8ymhsIsqPVnZKbq9+jrPUoRJDs1X6VCycaMS9bG36PFJwxW9y";
+ sout << "Be+LAmVi2N4wlBCmNwXclqK1URJRvocKWAKrt0Kn4dILU1Y7hXNPjcUx/0oG5Ffoh0f12glRsyva";
+ sout << "FJjtV7ePY1hClgBK9v7owd1YZUz9e10XcWOzS6L8HOpX9pocEiBdfO/oTDYBPd6LNk/E5V032Usw";
+ sout << "XdqReOtJL/zOBPW1vJ5xc1UMRyGxDeqUQFxCKLkFAQj46cG89dM3bhj+Dh4U5J5MPhQltLLhIVbZ";
+ sout << "qHvKkLr8cCYqSS5h/SOF9HWJKjNfXOgpRbR2l3/m8t71h6sSi5XR5o0NCi5V3/VCgAs/CfXCYH/O";
+ sout << "WEDkfZKw1IgO15FUghj5y1vzejXv1logti/MHvh3WqMlQ5i6B6SgaGmIbOdqNHdYUbQnNg41m+8u";
+ sout << "k5VPCiPWtGkbzzuzaYSx/Na14VdvAbZXDztFPbN3l1fMrAolDKlexOXohzVZhYOsqyu0xdGka67Q";
+ sout << "i/Bz6DbYM/U4rF1lWoX1Xh9eslMlBlJjaAPdicvaJF7YArjzLKOHB9p+EZ5tfrotIKGfdGIbt/Yt";
+ sout << "MSsyTx9PBINYD1u/JeI4SqXTwvWcfF8+ZmnspgnEabm8NKufPXhaJODzrxL7filfb0/JbL6qmf/b";
+ sout << "5ksG2XT2sPxBM3TjQE3DAtnS/Y3psQUGsXUuY8oGNF/PgRWd8e+Ek9IoAnMLuvW7S4D4MP/wmWTX";
+ sout << "kZzlpZBnBBvlh7H5yDHGYCwGUofjCiOk+4hU1LUNU4LGgZYUsfjNW+zbj81/JSoK8AMlmB/ERH+S";
+ sout << "yuBnOIDJNY7BG1n0q/YoDIU/YuM09fyzW4tAHNqfbxaYif2QldKZWbxUEiiOWaItpW4QTsQe0MaC";
+ sout << "h6ppkigA6/7DUgUy3PKon+JB/jdrUdW/2Q1qgLqV22zBLHJoq76n4QYZFmpLN7FkLFtabiXZigdm";
+ sout << "7y4GEh33CQIlETdes59sn/0qIUj36ICMh1T/ujQOe8hlG1EIruBdZk9CtprIsVYdpuiftqJHRLmz";
+ sout << "271Lti8HdM/KSVqrupdYb1GO00XOGVU4/kujCa/nzhCukpCpESV65sKSuIaW+VQlvYFATzX74WWL";
+ sout << "bKfIvaa0TLR8pMz30JVDT7f+I568gRLEMsBdtMnLyJ8bgkPGdngpnz4G9FBOqkDeZdb/Ji0aKN8v";
+ sout << "gwRZxrwUrjBE4EjfcRQy886hvReIP6GvKax4bwVcGfmYGdNuliSsCsPC6pLXSH3fnmYBHD8DbGct";
+ sout << "Q7dlu1Z/aFTO/uY3yup3clLe89WTrPTK/N1lsUDULj/gPNwbWY5l3ay7YRoTFt49EjYPmx6wz3kc";
+ sout << "YXYzOroiVWGspN9WfmHL4XN6pXWhiCOrMRG2Z43vbdUnqNk1992xy1q/ZHTw2ikxIwKy77wygWfx";
+ sout << "28l1Iqj1k8Km2Ci8sBy/QCLnql6olazxv2fxn6vj+4QNrOcJb3sDuLbEm6BkUHIoiFzZEpc5nIpw";
+ sout << "5YBSARDuvqMt+01+ed7yBUTms08EFh6EwPIsJ5R/6YE/Qt1aP/hfB7nGWlpGb+yqycdZbUw5XyZm";
+ sout << "pOEHQHvW1j30bk27jCRHzktRYXRXQ3BpP+gVcAlXgxeoARjFfC3hYPFtKSQsmKpGKOFFMdvdO+qI";
+ sout << "lwrru0fgpd0ctBiPsWR4loLRLpt/GHedyVRF29GtPPfP+JekSMDzQj4/73RZfIdHlc2b7zX+JdLz";
+ sout << "Jk/4yNb2NmUnum55ezFqq7sv4HPFvMBuOth14QPJsrT1f0NyUBP3qYocsTAY7yo/fg2gYqLFMBHK";
+ sout << "+N9IvtHqxyn4actl6t8DIHeBTsM48AJVza+LkOrmuK6k1x61G5r/qyEVTbWVMqKagbySMYtIyJxd";
+ sout << "G87XVnI5bbsfSdTdTSQ2EOry9U2H3HIrKIFzxOcj2NxJ+dNqpiLtreoN8XsfLvfM/46NeNaynG17";
+ sout << "jIqcV8TL7MVqJ74/OYv6Mek/0vjLysUDQwPniEkka91ZCJboXzsuW41M5QkSfU/nxsD05TvQVbFj";
+ sout << "GBNApTN8Oe8miBahONkbfBB2ks536yBwG8RXWGSHR5Jdl6yhUIw4mWb0WupVEd90sZmXEYeP1q4K";
+ sout << "MvdHRuEQbNZfyXLskOtwKsFAqa9ebN6yVdM2tIOOp12Km3mabcUct0nOq///UyfEclOfrC5km0on";
+ sout << "WWXFk++6vwChLbG+5WCZl5SNeuxEWu1odbh2XZ5ng+XSz/T2P2l3Fa7ujEKilHAYYbS3foWHO+ev";
+ sout << "sZlG35o8e5wuKiqnf7gGs8tAIFFyONtfRZuGzH1qy5W7BysZaohtU3ihEzJdomSI1xKHE7+Dn94W";
+ sout << "ZDi7S+Qp6VKbepW6JcdWctmtXyncC5AW+UzquyYuJzjoDRdVe7uEAA44Fhc7nHFHx7snTuZpaYcE";
+ sout << "OfIBgzr61aCpVMKX7YJ6NOzRNgfTBIMl24JybjFG9Mcbk2qQVzKQ+w1StjfGTEexWIfYRDxhoUzB";
+ sout << "I+2cAA==";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin, sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin, sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'frame_000103.bmp'
+ static const std::string get_decoded_string_frame_000103()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file '..\..\examples\video_frames\frame_000103.bmp' we want to decode and return.
+ sout << "Qld+lmlZhXVX5NDRWIFG1T4+OGdJbkmxAXXdHZEtpDf6knVTlRWyAhgv85Tf11KJZbhKv1dcsKtQ";
+ sout << "fX3y/9RxoGwtXxwFXCxbBrLRaklZ0wCJRoLkFEbV5T2V0aJZQJTKWkAqP6JwJ7zPTyCiJkDRbGA9";
+ sout << "1cIxGeLInzTUAlhbGO8eexmWzXHz6KhgZ87K5c4n+YcRjVfwTo3Bl2AB4QPv/bs5da4g6jZd7iwv";
+ sout << "PYnF6pRCiwuiCobwvi8eG43pWnNEX2bIUtfMVGP2zA3e9Qg7Q7w6/KNILIYSXeI4KjLlnmC9YPB2";
+ sout << "2qPH0Q7DVlBLBBUHO8lZaFg1gR2Jb+4rgSvuUg6JaoUbqAUMaFFnQCjw9bwdN4bJ1GFXCu4G2afO";
+ sout << "/izIyq+QxXHIy/Ez1TZWTtkJfWRkKAjj59IBD7fRSqyvL2tSatSiYQffAcsyQJzcPMTHahKq3XeO";
+ sout << "pFu5XOr3OsyxVr7ME4/GAOcUjNpdW5pAMPNddRfL6/Jy6S9ICHxppdwhMAtbxsaHiKv2xgcc/t3I";
+ sout << "J0t4NPThn/QTNed+F4iFR30+lwrS1EyOUiqRT7q51LFDQE+/ZyqCrq8vEGp+BRAxMEoL0ekA2B9W";
+ sout << "vceyzfAlymEivr89KSSC9L+VZjE8qylGshgeXM30qladBEU4CKtcTlfJFWSHZX9Gm8qDXmp/5bX1";
+ sout << "lT9/GNd2E1hBWWQtmQ50DMlInp8oFsoURaMgzNu8zOelG1WAD663IxutR2wJY6ILYQfXNND70XrM";
+ sout << "O2PI0ZVRWenZjLzXtSefvwSXCG1G2u5sjq45P4Uk35wtetzV+N2WzVinM3yYtcABa51N3Se2nDWP";
+ sout << "huxbCEVYT0c5sfaNCy7XRQ0ijcrMdqMDbecOuTMSlE8FEu12Z0cNFQqao0R8q3601D39vmJoxIPM";
+ sout << "wRIiHH6qVcCMBV3oVPWIiD8T96pUZoN3V9BpyQx43MEC6ZdVFqUVQtiYu/PgWqK2pwk4Lh4vpou3";
+ sout << "Jad9ENAsLdoVKZrtHlD8k70MVFOXNXJELqJarxwDy35JAha1+dHBvcgU3q/8pOnhS6xZ6judsmXX";
+ sout << "LVBdUnKu4w/tbXgJA7lkLtwtODiXCL6edRCSkuXmTRLqXhrzUYzOVO3lZQSNWLLagHa73ce5B6Wu";
+ sout << "rVTjMEVaNC3Guz5/cOkZrveG7MTk/eKR56x7MhkDS3H9pbNiCoqO7Ub52x7j/aicE48SYYkXFTrM";
+ sout << "ETpxS8VFa1i5VpaiDxhfZKKV03S/fA0QoUcakVISiSN3VgSrhYsu9KvVjD3kjW9IMKGMlcVH040t";
+ sout << "1cs0rHtLRVh/FjpMZlQxWxhI9ZMH0Ccfzpr7SbTN0Y4WfKaO1O/JfqYkzCnFTThvkrUMAeA1+zHJ";
+ sout << "1HS44rFnT06RSAGFX6KaqrRFBOC3V3ljXEHyyrGJJe0OHWTUAwov+JzoXuB8onm10lcxUpV2Wd5R";
+ sout << "RZ3dx/u9pEYgBolzQIXVkcE0YBYmkXMJfgXK3Rp6V+1pIR9bTWUU76/0CgMHqVBKZOtpl1ykTQ90";
+ sout << "h/n2Mcjhmo9BtRIi+R7rBhr2a+oNj7GZHVPaaItTcdSvns42OxGjc8R6ZdzLHzNNPYx0NkbVeKnU";
+ sout << "FSV4qd+iYq+N5hiPeTRfwdLU1wRL84Gvm+JfR3Y6eK8dBmMGCp0skspHGgpf8xTXXpYmOuZ1FmXV";
+ sout << "YMKmrYMuTm0IigxtpmCmHPmRZ8U9xbe4Oc8UDxkkmCUvcuvMLS9SJKFOQiUJwxuXgf2IzzzePLcx";
+ sout << "ePs3jrlOoD5GzQzSvDrJRIeSxjwTrVFiFT+qwMIIAR7TyTjBOWV51+kM0+5mU9g89OwLmO4yxXes";
+ sout << "F++dusUFHv+DGSCxk2iGNwiNDQA8PktmdVKux3PpVBxWZ6P0W4Kyso6RNIXk9iAVZj59zCr9uPwK";
+ sout << "MzIZ1ASN4a7lrfvv4cD+Uxovvt1s8Kck2wmIiWg95RiLdnopqSg8qZY/3U5u6XmXCqnEFTYuKKVY";
+ sout << "dWsDem2GxTTNM3DtxFN9fYbHN6MdbuyiVRPovBz/T+9AYpx0PVaFst9WVLbf8Ph2Hs1S1vgrW5sS";
+ sout << "qM3lBgjEYl4CvDzL5HbmqBV1gTOZrzkrEdr00ChKzRURvTBn7NlvPZewMhL+Hc0SVXYtzCLSl+p4";
+ sout << "C3tIOZaI2l8JIt8k3znBFs3UrWx1WGCv3GY8HEsTa6uX984B5dVvdlUqmstnqK0FgMEkYxiPWoKV";
+ sout << "eYlx3k/sV8GChiZWY/0k15KIY5c1ZUxBQezRc6a8IwYeuCK4dcfkMtn6AUpWu3W/vY/sx4dwNNaC";
+ sout << "eWhKda7lBCMsfRdeOZvWgvFKoIknjnkh27uEJu0AskTF+xhdXdKwIfM2ThYFipLGAImNXGuHbtlN";
+ sout << "CJ4FBcpn1BFWEY6E4Q+UeOlU1rv//LgKYxgNC2GX64oLOAoPGgEOG6dTKmnad/7y42k+kmQnvLvT";
+ sout << "YNkffPIcqqBvhZCmvIg4eMR+cB5Kw5IN1tik/XNmrI2FP8y+7OhNlFah1F+slgX9oHVKoRLtJFPT";
+ sout << "e4rQDWqAnWMAoSqsITbHCq9Em1lP6Cq3anR7zsCNH79KJCsbZOZ+J9ccoLm7uLJQUl9BW4irlZH8";
+ sout << "fYZypsN59YE3kzHivG1xH0QsDLXrw4G9E2Z6CFojySfluCPiHXO9V9XxiMaU2X4uYHVb7ehs+/TX";
+ sout << "h8uPIngi2rIspfThIzUPC8nl9k8xIH1BoWhryXHkzPi4M+ZAI9afBNr6dB9qa8O5gPvcfpeWPRvB";
+ sout << "TGAw+OW3GX40CxJhqQ6n1G101LjjbFvWWdHTm94cR3cS4B2BYzfAqy9Fe2woNh8OT9520VCEMgWc";
+ sout << "4xYjf8rbQFq3kBgPDVEyu86VZCdVBaAs91vTnfd1i7tKCN8JECyr04O4qJ5IM1+5Mtv1Z6wlgT4r";
+ sout << "NmW5FaCZIKwfORsXG55kuEeKBmvbnBUd6iO+jVtIn3D3RjWCHS05cBsw5uCvixNIHXIF48lTiHpR";
+ sout << "hGITp+vcydTLUEeVRxnlKIn0RJX0Ht2PWFNNbU0RV2WFS4K8QGQxekj6i3XFsB0UWJn7ipi4eHJl";
+ sout << "CIP6hG5bQ0qG1tvhC3a+Ve4et41gI/DZu9LbSqg3oNWUPjEgFSFadjJ6ZByhJ3QTm8Pl0uVdpzra";
+ sout << "myKEafoz0tbaRgJgqAGpQwkIPgp1ocPZBplMSbI9zjBhrTlI6fXfH8aOw4FgB6F436yGuVl3/Rjn";
+ sout << "UuvOT27jH6TvUOGxWBbzXXcxU6250E9S45QSh17Ly1/pfal5GdAcemaHKLRBeCLMwMszIr5ZOM8M";
+ sout << "LxeGCXvWuMuoLIPmElzolFuKKEht5zAr+KGbhsILlLcVpQBnQRM3NxXfh6bO86V/lEOZxhy1b+Js";
+ sout << "1bQrn1Uj90QnhqDoI8t1P6aSFDWKvbsnzC30gPZ8E+FFTwsvvKlzijcoroFQ6I5rSdVehv8/YNvf";
+ sout << "1yYpXA+hIK5wbbyIAXxxmi+5OP2viwGEihe5rwkuHRTmtJJ09rHWFT2TbVQAF7775ZFNpSogY57b";
+ sout << "GJVCa9pBGN8qzsahk99Z3tjeP+fP+4F4Si8JyPJq+xmTO62ciKxHrHt9b6sE9H3N62huURtpP90g";
+ sout << "91QbEbFJU/5JSPfJjJZIp299UhafpBSUACpOnnjBJT4xhVU1E3k5x6TKdrZYzAC/dsQ7BEwZgg+W";
+ sout << "5wfLTnkJsuvMLQgS5e+Ot/EUNd5+16kkR/wFeH6vtzG0EyxkWK4V7GrKtsrLWV7jOC6yY2mGwfnB";
+ sout << "iWLdaI9Wj9pIeTk7w+PcyTZZfdDldyOF9TwYKvHAz6ea5s7sUe569Y+iDqOOXOwpjX7TMUVgyTCW";
+ sout << "4VC8ixQp+UNTdlKLoeS+2fw2QupH395hLQ1DHBcO5Tuil8Yqxxw6nV+j27THym0CaB3j0JgA/4Tq";
+ sout << "vbqsEonwHgSaP55u/j+0QRpycKoXfEkS4gh/qMhbLAPQyTNY7QLjE5cVUqzLG1twetMMcXZL2Dqf";
+ sout << "dP2uDCswsX+RJdIAN8BFoa+J+uXHgBMgbxO4DrGz8GxuSr8RfS0JeEFReLiLpE3n+SrnLwKAUr8y";
+ sout << "qWjNrqRD6XKVWpX4SY1I6wcE9/3jX0c27mGX+87XnUZdIOZbNgXmntyS8J1P4uFaEZIy2rC2ahgg";
+ sout << "1mdwALsK29JJ5QEaSg/qd9UEmm6jnWLfquCgBIkacJgjG1wc/029kL0/Br9t7tuI4jPiKKp+XRM8";
+ sout << "ZZJGwjcB0DbJPB25JQ7zp01lbnEnNiGpNkNXUQtf7a9Z/F530W0M6wG4fOl3lW1HP2zF1Ad0GJxK";
+ sout << "y9g9bj+tCsfJQfeymW/5xaC1C+9sEDOsg6hgVH6avh1a0ILiY/5MddtCHDQKQF5tgkuiKXG1+ihQ";
+ sout << "CUlFov0Q7HG9UruG+eydcYSdyfKkdTqYQ6F8PjLP/rpiypX1jiZAodzEuvZwQcZLAgp3gqV1swZw";
+ sout << "6rm2JpyS2Kqc4yCanywpHAU8LkVsjbPTanJiOgDguguVRtYGpAh4fTje2Kofw3rbPjznNu+CC6+4";
+ sout << "8QxPZtcc8USR2EShYVlE90d5uu13F+epClENFc5hww6ymXysLDCIop2vM0PuA6csUxJqf6YFZHBm";
+ sout << "c1h+7m2ULTr7DEVeRCbDkLvrXrL3zzqESvN2x7QDUW1lQRG+A+hLKS/nuibs6tI8uCZ0I3/VDQKX";
+ sout << "hAhNjD9x82FqKKyPGFikNASTaFg7I1DAHm2iHm1Rbff4I5S57UUIk5zr4o/pfQBh12XxfpLtvSfn";
+ sout << "SGXRAUcTO5jYoftuSmX9tiMfjjSXopedLWjMKSUXE6m2yggIzxfAzd60Zyr9lNMBVzeXTSkrReAU";
+ sout << "QjMxJ9zsAF/86q2lsxr4gJKNmg9QkunRbsVlh3OXE7MkxBHlb2MkULioU83Gf8LiosiEEmYSB5vY";
+ sout << "H8D6cgnXtB64BWoEJpQuG/R+zvnrWNHKmcBd3YkEi1j0dtL5G50SlMOJuai2xsD4RosbPEdV6Qx7";
+ sout << "ESWrAO1naNHp0fewaVl3d8qXh2rFZAKNZXP3O3H7h3BAoMOsxWMFNJwQ0xZshhRvASlOr3Yn3HB4";
+ sout << "fOqqLiPecX/o5r5FRa6qIfP75QaKqcu+iA23psV4/bszP8L4wREKioaSFncsUwsMU5NyZn3hPDUo";
+ sout << "kdW+ZGGQk1F6Md46VYMIvSxC0xer/NcISrDfWmae5WCoGlJGhv1rSnSjRmMrj213eEh2qpDNhz2C";
+ sout << "8dlByOZtSTOPejh42nYMZKCdBTK1lftdSeYdsHRGt51TQOauYYNjCwQkh87aW32Z5dsUi6H96k/c";
+ sout << "NTnEoTZbmyqFdmov0QyQBgIfPmIUV/z+3x9PnfuVHJr2PBdElqqgp7h0Z+Z/7ESnDV+G/0/dx6nf";
+ sout << "hfktS6/8axrd2xTKr7VrfBLvasV0dTC/GibZlQ1hvowffGgH8dgooP+Nc/S2UqhkYuMZz/Df1r5g";
+ sout << "jYMY3rLQt3RqpbZmwU3p9MGe74SVOSCLgYXIDQiGyoGGPuwRwj4uhI5f26fC0UzG/0RCe2g4dDe1";
+ sout << "vpDGatzd+3ixmyzEf6K+4UU4l7V7XAuUYs3lGEmtkz9li9mF3huDAUgOvvw+jErQrMnUGeyfzqDF";
+ sout << "xyGfB50sK3Y1q/NSxYKQ1oHsyNYvnTr/aD5OPgMzbjv1Ii1mnwtP3m/EWmdSmAsvsjEq6Dy/yBuv";
+ sout << "WZ9JO/XtxbusYXBNUxb6lU00DpJK5NGZVxv6UiQmrRqZvg531ratwkkaH0ZJSOwOzWlRAeVKiDPM";
+ sout << "mxtnqoUGNcyr1SqIHBHvhFpr2BJKEeZ6MRwNHoQYCA1dQ4l2YJtZVITuL/o0SHNq1EXC+5sWB00T";
+ sout << "UFfHRWFOYH6/baG2GJSvgzQrxBH9miEG4WzXQcdTQlmup0RZWjnwEoyHRMj4pc9cujSsTMaGktXD";
+ sout << "ZzkAX52IncX0jqq2ZE4epQnx1UHg5IXANgb0Ed0y/FQjS24SZ57uIvl396ubCO1LQ04vGH2Mvs/m";
+ sout << "bSM7jKGtcvjQ4uvVaCyk29Ek4EKJM+gUAuEj3IcKnoRNL/P7L2NEBlJuQBlIEgczCVG68kkIOFLZ";
+ sout << "CqGgbf9IaBULEjthq4Pr+B5bUYmoBGtkUDM0KewVRJ+YA6A62AAAeStbx+myMgTTqq2b4idEllZn";
+ sout << "0Hc4kztLuBgtHfwaizv9gYEUbgKbXQWfTQdUNAGSyKyeY5dQ425q+eyHezNiXZ7C+tDiM2UN+Lg9";
+ sout << "t49U+7urUylh189bDcZcGmbx10unLEwYGT0CgDPGA8DJRlkHUkXSlImHpz8+3hjRtgljVcz+kFXi";
+ sout << "jP8F2VcEoiUDRpaTwdJTi4pRsWSZF6pDEvHWntpnhtBI51zoDzEpbkHJbjRbvBA2zl0b2MqmwGXW";
+ sout << "2qDOXOfSFVUVzTr7++omJ+UXxq9awcr/LVXz2tsuMyIvREj0Fx3c9jVozDSbOPzn97QD9LNh8Pau";
+ sout << "bvPgfmMGz1Xj5f1UuKvUiCfvfP8ZZs5l08ChMadB64ipgmdWKK4adqE0ES0cTqcg+pJDDL8FgLYV";
+ sout << "susPETHqp58vc13TMcBaqMAa44/xA98rFy+KZpYNxFf+l2U1eq44OH/zdytXhOg6y8TWrKYIdX1A";
+ sout << "C91FZWXj0t5KfTahGZE5t0nP5iKl1IdXnE+dOIvIHuzrTnyjM+IiHmj1DxClG1VQXhZcwvfBzIY6";
+ sout << "MRwFxUJXmt7O55uesEbZ/anmQB6LHdy7hMuvvCgeLBhoRnnyiRJYp3OAwNH5MLy7LXK84ZKTkodw";
+ sout << "BuyRw5oJ9KOB13Buxj2yCRhLky572BT61cw0rXXkw2ZOGQgzHbO+cjikNk5LsVyMYfE49ClKM4w9";
+ sout << "6pVtXDNzSPvQK0KSO0ZMKPDAr1/MrV0PD5Y2v1JIVPOuKSjq1s2vP7ypzarrFHAJnsD1FrigYXME";
+ sout << "9amdaYhCmPIiOjj+9xSfmuBrrsHJ/THe82pg0fO3mpsF7TVY3zQCpiMDY/UqDyRrgc8NQu6A2WRc";
+ sout << "oGCRQ5QCWCTFhbIV1HQ/KXjiCeFrCd88KkZDLDwrWMqeeGDTM8eWQcTIqoMMtu/JiCrts9c8yiTj";
+ sout << "IFiHTXnpZMYwxDeT9hvNkifueXVjFYbEs6hHySwX0kcUSgtRP3fUKyQe+Iz+u/iOi1tFHQgPsV5W";
+ sout << "gltpMLE72aQmlQ9C1lYkJQoKrQJRFiJmiQn5S2hQKXurP2HOIsAYSpW4mpeeFJpxsF8lekzeniil";
+ sout << "96nrrpQlpc1vPdDhbmTY07tGoNlYRjoKTYaelkktnWA2a4n69x+kD8iBfVLANU+EFHNfCyQgmdJe";
+ sout << "fWMYQwqwgxMWk88peAftdx7bDJ1ZJQ4q0zzkot7w7NB4oe0Q66awUwj2n4DYvDAum3SRz2LwsaiR";
+ sout << "Ke8N8dMtRYN2mosZ/108MktIKlnJ08bkI6eDnO5vHlbeBfLOfEP++jGsgdS1KHrZHdIygtioQ9Zj";
+ sout << "RzWb1fKOpoIbxV4mgh5MwpliqwHmG0DIq1UPIEqj8W/Vbd1T49FhWRJs8cyYraimx9MPklhyxlGA";
+ sout << "HvHpQfuihMzLT7nNAVceWz6GzYfHy5uvje2MYBVHkoQ6RaMnJUCfFd64pbFTmsB+/+Teoo6q4I5G";
+ sout << "fbeIMh26cs37X5MwocXcq7jSunVLgPJYDlBcbpIdhDt+Uuf5VPo1GXRAk80ouu1E9mrYvlZ4sanS";
+ sout << "5EJ61PNevEOSDPPdYWwfMR0rKZuoefUCNfvy7XyXpEnZpNLHKsO7Cs6ZyL6zQykBk+KQCfdRnTHa";
+ sout << "SVSpKvmD34O1gGkrq7kSfyWO6eU0TU8HImJY1tpI8fcMTheZ24hxx2QsV6IbsM0wbxS3d2Qo15XC";
+ sout << "oP9xQxVcn17iiHUg70awt7j2VFEuCb1QjMbNnd5lUvjSJ0jH6gi+n/on65AWEJYm73Akn9i3fP+v";
+ sout << "oLTDxIOmjRZsDgzsAbgtxb0Ozu0rNutnPRH0Am9C+GGJX78X3u5qDVn0q2+qD7eQkPOmW6oQiIYq";
+ sout << "8rWM8ya2N940j+H5HsvyW0FKyrqjSSXQ5fF2LJE27Wc5ob0tVuvWAzOQ8COZWMMapu/S2C61f+2s";
+ sout << "dFiCjJQqvr3Ai3pePmVrODBGROVHow3PXekC8iQLRwOYfNHwiM1jGwPOiMBZ3v+LghoBYHhmUh0Y";
+ sout << "kZUb1j5Mncmgz3pctYS7KFhlHq1RHTDlF0pevtVLDXyy0QNXFoOqGydJaqLN2eILSl/eOGmsVlQz";
+ sout << "lgyoCzPW0YsuN7Z4m0z0CfdP7WTpL4s2jlB7QpdaF3JOaip2nVZzX9xb6qXPosQ1WF9yixcznoAZ";
+ sout << "bfWnipe5Lnxm+KHX8OUclbWUC6Twaxoq9Uo9jXuwkU6PZ5VzM5lao7D0JCPfVo7b55q1258j1AnN";
+ sout << "9JNYYcZ4ZjTEKvbXGdtb943Wmmr7CnI4IyKv7AFpeiMAYPVRgxIvn0RjWpJ6lzV7LutAjv0HXwZ7";
+ sout << "5XHtqvvuIe+IIIG7Iqj+JBW/pgQsbb7CKXiRmrWwl1MTtDIrQuh6UP6mstikBOF/d+yOSqCvU71B";
+ sout << "A/Bj8gEqiPEqB7uih1Kakz9wRraRAYo6VZphC8Q5LdkFQG45Bj7KnACHbBs7e9xe7GDrP4OVbQHh";
+ sout << "m5QCONkNpd+0umv74Adr64LDpsMr6CLBgHRrXukUXUGmFPqUCD7lC+quhu8psnZZrvSNPSa+goRp";
+ sout << "PnO4wDlSeBSkuSdyC7utuC40jQtIZrkJmvkq5UURj4VcltYQ+5KiypO7ixAK4fvKyBTgxV2WNVeY";
+ sout << "QvxNeJcNck+IPEhYLyplcLzyoekhnP4ZDD6ALG2jWZ8QoKpShA8+HdRSJoFguoERQRS7ePlMxywb";
+ sout << "kcLPkcyEOlBu7lSjCRvjvdROmLAidz2GrlWvkuLrRe6clvs+U8JfBTjOON6P5nq41ElWNA33r9KN";
+ sout << "kcCmEICyFl/Ier/YdjOUtXaHsKwHaMjmrXHQOTP7ELs7jouCbb4cTFVtgB20smKj3paJgoQysxmq";
+ sout << "12Ur3QnHaHjaoxzIQnlaD69TF4O7T6U68/C6BwQDuZiD6iB+mkCQ7Uz0zFsiVMbF+RgFJKpjN4oo";
+ sout << "SuR2gUL8sPlixeYmannuPwhCkJ1swN7NiVeUwTGFUDeQt2eJvJc2CllOpUZwF9PbyHSkxkQLs9kP";
+ sout << "9DkvDhKkqJ2aEHDlPGBjETFYjNGdoBfMIcr1yvWshl9fTGlEi8c7mxMW/5Ed4sSdV3N6qRj3KZB7";
+ sout << "zdQJ4Ql6tH7zkYWfo/ZtTEggQQAe6FzyQ12/xgFgdAulwF1IJZ/JlzY/SKePQPX0/89AooSUAl2q";
+ sout << "/BfEFEI5XJhXDp2VJevsfFAjlmf0pbC5DkyBlUwdStZAoZpvfZPXcQ1NshCuD/hT4FinYmLl7GaW";
+ sout << "LJSXkHegN09TBLWDdWe3DfKDZEWYqbIvtgt5Evgtw/5Qvy5DtefyHPq21BoIT8C1zxkgfOqEhH+l";
+ sout << "E/fLaDsROj+RUJ055ycF9Wa8mzCOZMnaqsD13eTXtEY7LQ7MEo/15S1ny5JxaGNHxy7YJ3JfrshB";
+ sout << "0pZ5vL3jvb9iYwocPnlmFpli+Md6qEdonEN6K86WwcRNqV57mMlF/EhBZXi8VnW0nqglR3mT2xTz";
+ sout << "CKiwPK1W/zOnR2K0SsQrHV5kaLCfRi4vM3Jv/bGjlgJSUYBkB1QC7jBKE+uA3H5EmspwnDKPAb+b";
+ sout << "kYXzpMWfQbvMvzpumEs+nY/xbCf2Hr1vhZAAFR1L4F49xrxDr8rjP3DryRgtBquQH6/5qMwdg9pR";
+ sout << "4ACieRQts0S8jC77fxLAFW2GqifC5DBhwIcdhOhxR1FGLo5RzNktZkPob/fXEcC6u/Uz4v4Gy0j/";
+ sout << "ZM783wye39lB2eymWQ5XPGC9FKR+ZLodyKJK+NXDBiFBXOjY4WNKEghllE7jAEU6VVmAN8NDkQdf";
+ sout << "u6MiVlBZLK1cepTPDj6G/TGH2FK0I4O/z+Gb2WQdZ2VUObGhf3GpYNR4XEoBsJe0I8F+TKpHYpdY";
+ sout << "guyaXCEMW9XpK0hTOBXfaooIQu4+Yb9e18fKnkrW74Aj45mdseL80RH2RJGm8LeZa/Nluqm71cqu";
+ sout << "9zJkwZjxlfICDgLhkOXtt/Lihzoqav/abehnuZjlyWwJ34eIhCmEv9D7C0P9VE/7B4P1S/demat+";
+ sout << "W+rmgFScowUvs1lfxNr1I5uCyLEJ9VphPUXnykyJ0XM6zm2Za8jD17Nh82k/eCX+JFMWv5znDNQe";
+ sout << "aDzkIRjTQhXWt4e6GNZ5zU6g9rr/TIePeMJyRE4D09xOF6orHWMBh/TFAL6PQnJaI6RUqCg8le0+";
+ sout << "ySd9qWCRpZsYBK+bZBEV9A1iJyvhLyKLgSGC8Q5Y0tQmE5zWSlYkRr4YtfASRn7e4l+Hz+hhcReD";
+ sout << "F6s8jWCAHjsq4uZi8qf17LwZu2xpbSLmgCE1sij59Mli4sWlPDkX86ehGqvH2D2x3hKlXco1v+q5";
+ sout << "dbNe/zvwcng5KoCwL0pmT3itlXfQs08+1lXbpoqUf2wqmQFEi3/TIWq+1lF/zV+6ICVx1d1eKarh";
+ sout << "ZgdmD0C3QLlPNlUAG1j6qWQ4K32ICyKu2XWRjcaElm8uRxPBBJ2DKWJFyDwP8caoB80A2ApnnFCH";
+ sout << "mrijgRO7LeQ6bQJJjOBSjeppPm4jTsVd5tlAefLV25uRwx4Reif0e4x+24fxtPj9udHRWggwGu/1";
+ sout << "Zs4+wsJ7KmX2ekZ2LR5aotwtBCo8X1J9GaHal4WCzh9G7EqAeSjjrD63DoSgJx8PAUoH32QXUMxw";
+ sout << "b6JR8Czkimh47Uv+aIqZsr6GDskW7xfxxgmzIPwSA0cJkulJKiOYEmjcfgzqaKHrcjMRb4LhJRTE";
+ sout << "F7Xgdk4nJGT2hRv3Abqz4725TLPUsfd1DFTM8BJuJSWjGNa2cyQ6f3CTQPEZYFiyYMCtd4Ycytnq";
+ sout << "N4djAycInnDJV/+XSjC94UB04UDvkq5lds+tgGMDf5YWClAz5EO0ztmL5PIQrA7qx1ykF7xiRHVB";
+ sout << "Jy1Ln0oTEV9yf8jlIYILg3V/j716p61dkyJIvRtO6XhFdyE+4ia0WdXaNWNwvx4wkzqRHD4IxMD0";
+ sout << "imBJe7IIMVztDzJ7T4K61P7nzwgGJgXHwfdh4xxYZC+4Qf7LVyGOeH30AgAiZBzEFu6kCHmPMxgZ";
+ sout << "VQIAvbW0/84nBgbqTvUTQTVytf9ufnhuVZSJfXbMlFGTxeCtHG9C6rgAAk2QNPHb8up8NL4ZnVcA";
+ sout << "AWk0OHyU1DZrLFb26nmHBxwVZySrSppYbldjEYxMdewD2OIYBYrCBCKIJzZpTMP8D7QOIX7B05Vq";
+ sout << "zPH2i9cAAAWjZjAkQxG25u2KhBSufKHwxVZ9xgi82dPIUZJRMhNOyUQ3uVhK4MilNqxi3Giw2KtP";
+ sout << "lO1IWReKc0m1pXxv70r03E0i7kf19iQ6AAAABRagQbu/yzAW7Stqw18BH3pVGZSoj8no2Sn/A9QF";
+ sout << "E49JB+qp6BejcC0vGwH+ogKo7pk9fecrkHEc/6aH1Dt7ciMaDXfFII5rE9AAAAAB5kmFhDYODCNn";
+ sout << "qZy5bb542mHiW4BxDLW3mQ4uKyXFV56IuntOj0rsjRZdrOATffLebKWyn1anGbGdQvJcOZcHvV6h";
+ sout << "1Aih5pmFfPxyhA2ba90hh+kPYjhT2QAAAIYcLHepOiMlf+gULTiFNjbeyaz5vgWcGTiwkv4q4ED3";
+ sout << "ZLE0lb+l/7qt620m8kgPvUAOLnK6ysWdLpoTtevH7MY5LafF3R/YxEPOo9xgr7zDLrMKLkZILeIb";
+ sout << "yegmBAnGeWonZpv3eidKXsbBFhHGw7DoSakVKAT7Jahlmyk6howH8x8VEVpK1QNbaAXt/pFXGrzr";
+ sout << "dAO6LjOcrwxvW8iYPjPChEHqwYloPizhrN7k0u0F/oq/urAZxyJ/MP8Tx9afuHY4aocW8FIGmN8f";
+ sout << "NSozaWDqqw209VkydVcnibQweQucq14zNKxGZgvnuw3SKeLPAc40Z3fSWsEfG/DImcOJ6QdmY8S8";
+ sout << "34MKBXUjR8W0w1P0gs407lSQFRZBEmiOpU3HW+A4BisSe4fcFlzFt+lhP9VNDr7lBHpbAqkg1Ob4";
+ sout << "8/uu5w5qut8RiDJp2dYQFY1OieuY1lEN1BFYl4hoUuBQqGBpq3MDn6V40ZzXHl2Rbl+u2tXhNICL";
+ sout << "FPOFo0Y+7b0ppLIQGPAd5fBGTfMnibWFP9Bw8KDo9wUbvGslyV0ny303hYXO4TzIliPUUu+nsJRc";
+ sout << "pBCeJdyRvQUjr6BjCXrNVSldiB6oCr7e0AfMBU1BErZAhzseZYzzlIavra3tEOdW4xweFxOO1JNp";
+ sout << "BqoG5a9gozEd6VQvhurdttGa5jsSm/tEmGDZl0t14nN18hjVW6KCb0u3+kCbcCRRcFz6tZ3+eomJ";
+ sout << "TQIBUJu40uNzrLmur+zJyT7+JRRIq/xXSv2R1oJhIiYGe9P99wNd13TuTi5Oyx1b3hHJdysPjIt1";
+ sout << "/I8UGCpIQ/FCIEEplSCkhDgedfL9OtDOnU/+bI2cipB8tWSwpwbczIslv49e3+xIqBzLf/4gBDd2";
+ sout << "4ZYwe2lHWGL7OXGYCAQbC9ELg2KuRDpLrG2ad4fhUuAnizCLb+q+3Nd7qgkPXweeEMAbSHhp0vuN";
+ sout << "XSbVB+cDaHkw7DxxJR0nn4IhdbkuQ54G975t+Wo5uPunpyZ5QvDXijG8NEhIAytpMmhXjkiyUbk/";
+ sout << "XmaEnaSTOxOEVh/fBjeGfxHmjn0TgkQlw7GLHa1rB6Lp3y7hSWoZW0RSn0TmVQbWBFHen0cfhsp+";
+ sout << "zc7gTzMeFxhMf3ZmBS9pmigcVHPAmU+rOLTtAzaklKumgxf0B+Su8YLZpcvc6Jy8t6rJgCYwIhR+";
+ sout << "BiKEN1l6CxFeQtJp+2Do6oEZ4Lfk0DoAnJdV8l5DhkiXiuwX4zPFiKZQtKSBsrp7bq6dqjDphbgL";
+ sout << "1A6JahmxkTYcJVOnVWG6LvfHYCIJ6hwDV4J23P+tNZtLCzfHPnDDdyJCmBExsOV1xXzNeGhqZhb3";
+ sout << "kSWXntkMAstuTSdgb8vPGYSyEMsTx+pTeXFGv3TN+YCdQTQIovV2f0KTZMxmjoTmlZKueVeFwzSP";
+ sout << "S+G65EMEcgQUGloWsFPdIaRzPLYHUktOcJc4bqEDvwIUDLqfjH4zr7kgF6i0KfRUMP4Jrje78S9G";
+ sout << "C7o9XJLGWbS32yrdKVlIG+9f+2YQRrZECzhex6WjV69/JSe0jbilwXwsJSKtY6jFik8eE6RCZqN9";
+ sout << "c1vOxMcd+5twMMkmnu4yvBEV6Y207UtegGSHaESpEW1MTvbDk/75X46WMSECbeEe8lzlmNaaWyWY";
+ sout << "C+siHamjyTgHAvJLEwiNlQ26LS3mJr4HmpOVizbTykoe2WGV/jmUrhhUg2AN0CrS2LqriZolW/JX";
+ sout << "jJeehNlJ9Jy4e4NZE2Xn/Q5UC3zVJm3bpbC3JKre7sALksQSQInLf7OoYArfwgYmAdMWhgxRakIv";
+ sout << "0M0acqOuNUxmW0k4YEzEncfjSAQ3cAUkaL1XS55I5vm3o1RPiKBjjypzdi8GI7migOK5dRrIctP4";
+ sout << "U0S4L6uojFipn9VGhIjGiv0Rg6OcaZO2FDq9SOGmLZ4b92sE7v4rtEt8oxlbbxPdgT6CLQkVCCJh";
+ sout << "uvjCIeAmV0wwhaKYzE2TpSkPFrtCPWhBjSulx5OwEGvdgzUq1NAnHBqlc6Oazt+6Hb/b+zpziei2";
+ sout << "huprTtScOqJcYzqJYGIwYebjxpVM0f/05a3LodBUWUNUIRNyzJpyEZluHCupDqfEgF7ObUDvtTDO";
+ sout << "Zl1aCRWbztt2W0JE7SSCAZbzY+3Dq+m0VUJj1L7NZkg5py0mUHHnz2lDveZjtHr9UBqETzN2xCuw";
+ sout << "8LQqbhDKR5I5ThHilGjZjxSN4VUKgBiBNUHXu8D2VN9RHr9xjQzmnSOJPHtcFuf9ioGO43OVtV+I";
+ sout << "DvE3YjEt53F37uZBmvTQD3zcBvgRoNF24j6jjTeHE3I/MROKotCIBkxk5AZTF9Awzha4XwP3xOAI";
+ sout << "FyhCle92a3102sdU/azu+1n3Jq0ZeifCSicBjrAHgQpVM7afn/yha/YKXqiwingX4pvrN6IRKADv";
+ sout << "edJG6C4OttSovas7ayKdaTWURKwQWQ2NQF/24DUEmfGkWgk3e1uFjfdBNFez7/omGkRqvSAoT5pe";
+ sout << "rXpbWzb7nigtdMRUdVMdzAHooSObROsbHc7ngUn6sJ6rD88EJZH94kk3adWN6plDDTyRe/eu5Ah0";
+ sout << "XnBPmYIgVSYSZ/X6BvS5AZDElImmABuvuLEjOQ3Ydqc1NQIGOgMzWhn/Dc94YMxSOdmHCo5RyGjo";
+ sout << "Zn0wntZDa+gKaR8PwzsIi+Q7RvReVKP4xKNPbI3W47v3sh1PeidJXt75OoHyKpoxJJcjwB8me4iZ";
+ sout << "ctKBz0QZ5ZBuywtn2Lq69I5nmjHQbpIB+zmPqIxEJOworB7Qg6thkda97KcHsRbMJAA=";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin, sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin, sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ };
+
+ correlation_tracker_tester a;
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+
diff --git a/ml/dlib/dlib/test/crc32.cpp b/ml/dlib/dlib/test/crc32.cpp
new file mode 100644
index 000000000..32f67ed3a
--- /dev/null
+++ b/ml/dlib/dlib/test/crc32.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <cmath>
+#include <dlib/crc32.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.crc32");
+
+
+ class crc32_tester : public tester
+ {
+ public:
+ crc32_tester (
+ ) :
+ tester ("test_crc32",
+ "Runs tests on the crc32 component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ DLIB_TEST(crc32("davis").get_checksum() == 0x0445527C);
+
+ crc32 c, c2;
+ DLIB_TEST(c.get_checksum() == 0);
+ c.add("davis");
+ DLIB_TEST(c.get_checksum() == 0x0445527C);
+ DLIB_TEST(c2.get_checksum() == 0);
+ c2 = c;
+ DLIB_TEST(c2.get_checksum() == 0x0445527C);
+ crc32 c3(c);
+ DLIB_TEST(c3.get_checksum() == 0x0445527C);
+ c.add('a');
+ c2.add('a');
+ c3.add('a');
+ DLIB_TEST(c.get_checksum() == 0xB100C606);
+ DLIB_TEST(c2.get_checksum() == 0xB100C606);
+ DLIB_TEST(c3.get_checksum() == 0xB100C606);
+
+
+ crc32::kernel_1a cold;
+ DLIB_TEST(cold.get_checksum() == 0);
+ cold.add("davis");
+ DLIB_TEST(cold.get_checksum() == 0x0445527C);
+
+ c.clear();
+ DLIB_TEST(c.get_checksum() == 0);
+ c.add("davis");
+ DLIB_TEST(c.get_checksum() == 0x0445527C);
+
+ std::vector<char> buf;
+ for (int i = 0; i < 4000; ++i)
+ buf.push_back(i);
+ DLIB_TEST(crc32(buf) == 492662731);
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/create_iris_datafile.cpp b/ml/dlib/dlib/test/create_iris_datafile.cpp
new file mode 100644
index 000000000..1e19d2aac
--- /dev/null
+++ b/ml/dlib/dlib/test/create_iris_datafile.cpp
@@ -0,0 +1,65 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <sstream>
+#include <fstream>
+#include <dlib/compress_stream.h>
+#include <dlib/base64.h>
+
+namespace
+{
+ // This function returns the contents of the file 'iris.scale'
+ const std::string get_decoded_string()
+ {
+ dlib::base64::kernel_1a base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'iris.scale' we want to decode and return.
+ sout << "MU66cCmT9lCXWJXwhdfOGELwlyExClbHEF1s9XoqxNDV7o8AdVVHws/C9oIKO5EShH1lI/QFTWk3";
+ sout << "8EUdVpSw/NpZCUa7O9nq5uO6SE0gfRAyryH+pfIVL9jPiQi8rBdagDf4kUd4eggz9glwYnKEE+US";
+ sout << "K4GUBnW33YDf/jMF2GIBLNvz69yGJj8RC5rOUeJxR4mlHrDmnEfgRSdFIfXk4OQ4V/XbOsE1bnhG";
+ sout << "fmACcu7nYv6M/043Z6o8oaBeoJ2XK/9UqOWGFOwfVpQ46fz1a0oTlOzyDbbzMiniLr8z5P/VYwYd";
+ sout << "iAE70MwxHXs6Ga3zMmD/h1WxB/uRRph39B1lPN1UXC7U6SIatmtGWY+JYpwBk6raAnR3sblTFBNs";
+ sout << "UdPW+1a7AxinR0NZO6YEiCFy8lbpfPRZNAr5ENqPbD2DZtkHk3L8ARxSoFBgqPa8aO3fFow7rVxF";
+ sout << "xIJ2TxcHS84+BtH7KvtWfH7kUPOZLQ+Ohqghn9I57IeMl7E3aoTRTiVv3P2twAbP5Y+ZaAUoU7CK";
+ sout << "c9FptjKgMClUkuWxA7tGUEp069PqGT8NbI+yxorh/iVhkVhuGAzgjjXYS/D26OGj4bzF6mtRbnms";
+ sout << "Y2OYlF7QqhawZaHLtmZ6xLhR2F8p/0nrbpAz2brQLNKgQAMvU9rTZ0XYpuJNbRSsARkRDorPopDO";
+ sout << "kKNUORfkh2zfIytVToQ9tZ9W2LkfGZdWjJu/wEKjPDAU55q3bCfKOUk12tjq0sq/7qjUWJRcLSCu";
+ sout << "bqo8EzaKJj3cTXVgXXLHP6WEOPZ9vShuxQUu1JWkh8YEinjwFSyA6UnAKqPtN/HsBgv8YbnfnY/q";
+ sout << "e5JvUYWbs3Lk9enlhcI0vEVTV5f0GMjdkW87l3cWgmXJqiljJDREWEdKZJQ0rGBU/gW5kO3SAS1W";
+ sout << "OETVJG2kJD8Ib7hT15Mu2lOVNQYFri6O3yWtp5/NLHsYXoDKIYrxoJtM9+GkprVwRuhDcwxE+eQa";
+ sout << "pp5nC8qj38ameQHaJR2hJCuW2nvr4Wwm0ploF00ZP9cS9YznCO52cueUQX0+zil7bU++jghqSGP5";
+ sout << "+JyRzWUWWbDhnCyanej2Y3sqfZ3o2kuUjaAgZFz5pLqK64uACjztp4bQFsaMRdc+OCV2uItqoaRg";
+ sout << "a6u7/VrvS+ZigwcGWDjXSKev334f8ZqQQIR5hljdeseGuw7/5XySzUrgc8lCOvMa0pKNn9Nl8W/W";
+ sout << "vbKz1VwA";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+}
+
+namespace dlib
+{
+ void create_iris_datafile (
+ )
+ {
+ std::ofstream fout("iris.scale");
+ fout << get_decoded_string();
+ }
+}
+
diff --git a/ml/dlib/dlib/test/create_iris_datafile.h b/ml/dlib/dlib/test/create_iris_datafile.h
new file mode 100644
index 000000000..805291f07
--- /dev/null
+++ b/ml/dlib/dlib/test/create_iris_datafile.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_CREATE_IRIS_DAtAFILE_Hh_
+#define DLIB_CREATE_IRIS_DAtAFILE_Hh_
+
+namespace dlib
+{
+ void create_iris_datafile (
+ );
+ /*!
+ ensures
+ - Creates a local file called iris.scale that contains the
+ 150 samples from the 3-class Iris dataset from the UCI
+ repository. The file will be in LIBSVM format (it was
+ originally downloaded from the LIBSVM website).
+ !*/
+}
+
+#endif // DLIB_CREATE_IRIS_DAtAFILE_Hh_
diff --git a/ml/dlib/dlib/test/cublas.cpp b/ml/dlib/dlib/test/cublas.cpp
new file mode 100644
index 000000000..3f3cb09dc
--- /dev/null
+++ b/ml/dlib/dlib/test/cublas.cpp
@@ -0,0 +1,198 @@
+// Copyright (C) 2015 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../dnn/tensor_tools.h"
+
+#include "tester.h"
+
+// We only do these tests if CUDA is available to test in the first place.
+#ifdef DLIB_USE_CUDA
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.cublas");
+
+
+ void test_inv()
+ {
+ tt::tensor_rand rnd;
+ dlib::tt::inv tinv;
+ dlib::cuda::inv cinv;
+ resizable_tensor minv1, minv2;
+ for (int n = 1; n < 20; ++n)
+ {
+ print_spinner();
+ resizable_tensor m(n,n);
+ rnd.fill_uniform(m);
+
+ tinv(m, minv1);
+ cinv(m, minv2);
+ matrix<float> mref = inv(mat(m));
+ DLIB_TEST_MSG(mean(abs(mref-mat(minv1)))/mean(abs(mref)) < 1e-5, mean(abs(mref-mat(minv1)))/mean(abs(mref)) <<" n: " << n);
+ DLIB_TEST_MSG(mean(abs(mref-mat(minv2)))/mean(abs(mref)) < 1e-5, mean(abs(mref-mat(minv2)))/mean(abs(mref)) <<" n: " << n);
+ }
+ }
+
+
+ class cublas_tester : public tester
+ {
+ public:
+ cublas_tester (
+ ) :
+ tester ("test_cublas",
+ "Runs tests on the cuBLAS bindings.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_inv();
+ {
+ resizable_tensor a(4,3), b(3,4), c(3,3);
+
+ c = 1;
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = 2*mat(c)+trans(mat(a))*trans(mat(b));
+
+ a.async_copy_to_device(); b.async_copy_to_device(); c.async_copy_to_device();
+ cuda::gemm(2, c, 1, a, true, b, true);
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(4,3), b(4,3), c(3,3);
+
+ c = 1;
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = 2*mat(c)+trans(mat(a))*mat(b);
+
+ a.async_copy_to_device(); b.async_copy_to_device(); c.async_copy_to_device();
+ cuda::gemm(2, c, 1, a, true, b, false);
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(3,4), b(3,4), c(3,3);
+
+ c = 1;
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = 2*mat(c)+mat(a)*trans(mat(b));
+
+ a.async_copy_to_device(); b.async_copy_to_device(); c.async_copy_to_device();
+ cuda::gemm(2, c, 1, a, false, b, true);
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(3,4), b(3,4), c(3,3);
+
+ c = 1;
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = mat(c)+mat(a)*trans(mat(b));
+
+ a.async_copy_to_device(); b.async_copy_to_device(); c.async_copy_to_device();
+ cuda::gemm(1, c, 1, a, false, b, true);
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(3,4), b(4,3), c(3,3);
+
+ c = 1;
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = 2*mat(c)+mat(a)*mat(b);
+
+ a.async_copy_to_device(); b.async_copy_to_device(); c.async_copy_to_device();
+ cuda::gemm(2, c, 1, a, false, b, false);
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(3,4), b(4,3), c(3,3);
+
+ c = std::numeric_limits<float>::infinity();
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+ a.async_copy_to_device(); b.async_copy_to_device(); c.async_copy_to_device();
+
+ matrix<float> truth = mat(a)*mat(b);
+
+ cuda::gemm(0, c, 1, a, false, b, false);
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(3,4), b(4,4), c(3,4);
+
+ c = 1;
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = 2*mat(c)+mat(a)*mat(b);
+
+ cuda::gemm(2, c, 1, a, false, b, false);
+ DLIB_TEST(get_rect(truth) == get_rect(mat(c)));
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(4,3), b(4,4), c(3,4);
+
+ c = 1;
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = 2*mat(c)+trans(mat(a))*mat(b);
+
+ cuda::gemm(2, c, 1, a, true, b, false);
+ DLIB_TEST(get_rect(truth) == get_rect(mat(c)));
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(4,3), b(4,5), c(3,5);
+
+ c = 1;
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = 2*mat(c)+trans(mat(a))*mat(b);
+
+ cuda::gemm(2, c, 1, a, true, b, false);
+ DLIB_TEST(get_rect(truth) == get_rect(mat(c)));
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ {
+ resizable_tensor a(4,3), b(4,5), c(3,5);
+
+ c = std::numeric_limits<float>::infinity();
+ a = matrix_cast<float>(gaussian_randm(a.num_samples(),a.size()/a.num_samples()));
+ b = matrix_cast<float>(gaussian_randm(b.num_samples(),b.size()/b.num_samples()));
+
+ matrix<float> truth = trans(mat(a))*mat(b);
+
+ cuda::gemm(0, c, 1, a, true, b, false);
+ DLIB_TEST(get_rect(truth) == get_rect(mat(c)));
+ DLIB_TEST(max(abs(truth-mat(c))) < 1e-6);
+ }
+ }
+ } a;
+
+}
+
+#endif // DLIB_USE_CUDA
+
diff --git a/ml/dlib/dlib/test/data_io.cpp b/ml/dlib/dlib/test/data_io.cpp
new file mode 100644
index 000000000..8ced88008
--- /dev/null
+++ b/ml/dlib/dlib/test/data_io.cpp
@@ -0,0 +1,227 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+#include <dlib/data_io.h>
+#include <dlib/sparse_vector.h>
+#include "create_iris_datafile.h"
+#include <vector>
+#include <sstream>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.data_io");
+
+
+ class test_data_io : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ test_data_io (
+ ) :
+ tester (
+ "test_data_io", // the command line argument name for this test
+ "Run tests on the data_io stuff.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+
+ template <typename sample_type>
+ void run_test()
+ {
+ print_spinner();
+
+ typedef typename sample_type::value_type::second_type scalar_type;
+
+ std::vector<sample_type> samples;
+ std::vector<scalar_type> labels;
+
+ load_libsvm_formatted_data("iris.scale",samples, labels);
+ save_libsvm_formatted_data("iris.scale2", samples, labels);
+
+ DLIB_TEST(samples.size() == 150);
+ DLIB_TEST(labels.size() == 150);
+ DLIB_TEST(max_index_plus_one(samples) == 5);
+ fix_nonzero_indexing(samples);
+ DLIB_TEST(max_index_plus_one(samples) == 4);
+
+ load_libsvm_formatted_data("iris.scale2",samples, labels);
+
+ DLIB_TEST(samples.size() == 150);
+ DLIB_TEST(labels.size() == 150);
+
+ DLIB_TEST(max_index_plus_one(samples) == 5);
+ fix_nonzero_indexing(samples);
+ DLIB_TEST(max_index_plus_one(samples) == 4);
+
+ one_vs_one_trainer<any_trainer<sample_type,scalar_type>,scalar_type> trainer;
+
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+ trainer.set_trainer(krr_trainer<kernel_type>());
+
+ randomize_samples(samples, labels);
+ matrix<double> cv = cross_validate_multiclass_trainer(trainer, samples, labels, 4);
+
+ dlog << LINFO << "confusion matrix: \n" << cv;
+ const scalar_type cv_accuracy = sum(diag(cv))/sum(cv);
+ dlog << LINFO << "cv accuracy: " << cv_accuracy;
+ DLIB_TEST(cv_accuracy > 0.97);
+
+
+
+
+ {
+ print_spinner();
+ typedef matrix<scalar_type,0,1> dsample_type;
+ std::vector<dsample_type> dsamples = sparse_to_dense(samples);
+ DLIB_TEST(dsamples.size() == 150);
+ DLIB_TEST(dsamples[0].size() == 4);
+ DLIB_TEST(max_index_plus_one(dsamples) == 4);
+
+ one_vs_one_trainer<any_trainer<dsample_type,scalar_type>,scalar_type> trainer;
+
+ typedef linear_kernel<dsample_type> kernel_type;
+ trainer.set_trainer(rr_trainer<kernel_type>());
+
+ cv = cross_validate_multiclass_trainer(trainer, dsamples, labels, 4);
+
+ dlog << LINFO << "dense confusion matrix: \n" << cv;
+ const scalar_type cv_accuracy = sum(diag(cv))/sum(cv);
+ dlog << LINFO << "dense cv accuracy: " << cv_accuracy;
+ DLIB_TEST(cv_accuracy > 0.97);
+ }
+
+ }
+
+
+ void test_sparse_to_dense()
+ {
+ {
+ std::map<unsigned long, double> temp;
+
+ matrix<double,0,1> m, m2;
+
+ m = sparse_to_dense(m);
+ DLIB_TEST(m.size() == 0);
+ m.set_size(2,1);
+ m = 1, 2;
+ m2 = sparse_to_dense(m);
+ DLIB_TEST(m == m2);
+ m2 = sparse_to_dense(m,1);
+ DLIB_TEST(m2.size() == 1);
+ DLIB_TEST(m2(0,0) == 1);
+ m2 = sparse_to_dense(m,0);
+ DLIB_TEST(m2.size() == 0);
+
+ temp[3] = 2;
+ temp[5] = 4;
+ m2 = sparse_to_dense(temp);
+ m.set_size(6);
+ m = 0,0,0,2,0,4;
+ DLIB_TEST(m2 == m);
+
+ m2 = sparse_to_dense(temp, 5);
+ m.set_size(5);
+ m = 0,0,0,2,0;
+ DLIB_TEST(m2 == m);
+
+ m2 = sparse_to_dense(temp, 7);
+ m.set_size(7);
+ m = 0,0,0,2,0,4,0;
+ DLIB_TEST(m2 == m);
+
+ std::vector<std::vector<std::pair<unsigned long,double> > > vects;
+
+ std::vector<std::pair<unsigned long,double> > v;
+ v.push_back(make_pair(5,2));
+ v.push_back(make_pair(3,1));
+ v.push_back(make_pair(5,2));
+ v.push_back(make_pair(3,1));
+ v = make_sparse_vector(v);
+ vects.push_back(v);
+ vects.push_back(v);
+ vects.push_back(v);
+ vects.push_back(v);
+ DLIB_TEST(max_index_plus_one(v) == 6);
+ m2 = sparse_to_dense(v);
+ m.set_size(6);
+ m = 0,0,0,2,0,4;
+ DLIB_TEST_MSG(m2 == m, m2 << "\n\n" << m );
+
+ m2 = sparse_to_dense(v,7);
+ m.set_size(7);
+ m = 0,0,0,2,0,4,0;
+ DLIB_TEST(m2 == m);
+
+ m2 = sparse_to_dense(v,5);
+ m.set_size(5);
+ m = 0,0,0,2,0;
+ DLIB_TEST(m2 == m);
+
+ v.clear();
+ m2 = sparse_to_dense(v);
+ DLIB_TEST(m2.size() == 0);
+
+
+ std::vector<matrix<double,0,1> > mvects = sparse_to_dense(vects);
+ DLIB_TEST(mvects.size() == 4);
+ m.set_size(6);
+ m = 0,0,0,2,0,4;
+ DLIB_TEST(mvects[0] == m);
+ DLIB_TEST(mvects[1] == m);
+ DLIB_TEST(mvects[2] == m);
+ DLIB_TEST(mvects[3] == m);
+
+
+ mvects = sparse_to_dense(vects, 7);
+ DLIB_TEST(mvects.size() == 4);
+ m.set_size(7);
+ m = 0,0,0,2,0,4,0;
+ DLIB_TEST(mvects[0] == m);
+ DLIB_TEST(mvects[1] == m);
+ DLIB_TEST(mvects[2] == m);
+ DLIB_TEST(mvects[3] == m);
+
+ mvects = sparse_to_dense(vects, 5);
+ DLIB_TEST(mvects.size() == 4);
+ m.set_size(5);
+ m = 0,0,0,2,0;
+ DLIB_TEST(mvects[0] == m);
+ DLIB_TEST(mvects[1] == m);
+ DLIB_TEST(mvects[2] == m);
+ DLIB_TEST(mvects[3] == m);
+
+ }
+ }
+
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ create_iris_datafile();
+
+ test_sparse_to_dense();
+
+ run_test<std::map<unsigned int, double> >();
+ run_test<std::map<unsigned int, float> >();
+ run_test<std::vector<std::pair<unsigned int, float> > >();
+ run_test<std::vector<std::pair<unsigned long, double> > >();
+ }
+ };
+
+ test_data_io a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/directed_graph.cpp b/ml/dlib/dlib/test/directed_graph.cpp
new file mode 100644
index 000000000..b97976b96
--- /dev/null
+++ b/ml/dlib/dlib/test/directed_graph.cpp
@@ -0,0 +1,541 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/directed_graph.h>
+#include <dlib/graph.h>
+#include <dlib/graph_utils.h>
+#include <dlib/set.h>
+
+#include "tester.h"
+
+// This is called an unnamed-namespace and it has the effect of making everything inside this file "private"
+// so that everything you declare will have static linkage. Thus we won't have any multiply
+// defined symbol errors coming out of the linker when we try to compile the test suite.
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ // Declare the logger we will use in this test. The name of the tester
+ // should start with "test."
+ logger dlog("test.directed_graph");
+
+ template <
+ typename directed_graph
+ >
+ void directed_graph_test (
+ )
+ /*!
+ requires
+ - directed_graph is an implementation of directed_graph/directed_graph_kernel_abstract.h
+ is instantiated with int
+ ensures
+ - runs tests on directed_graph for compliance with the specs
+ !*/
+ {
+ print_spinner();
+
+ COMPILE_TIME_ASSERT(is_directed_graph<directed_graph>::value == true);
+ directed_graph a, b;
+ dlib::set<unsigned long>::compare_1b_c s;
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+
+ DLIB_TEST(a.number_of_nodes() == 0);
+
+ DLIB_TEST(graph_contains_length_one_cycle(a) == false);
+
+ a.set_number_of_nodes(5);
+ DLIB_TEST(graph_contains_length_one_cycle(a) == false);
+ DLIB_TEST(graph_is_connected(a) == false);
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+ DLIB_TEST(a.number_of_nodes() == 5);
+
+ for (int i = 0; i < 5; ++i)
+ {
+ a.node(i).data = i;
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+
+ a.remove_node(1);
+
+ DLIB_TEST(a.number_of_nodes() == 4);
+
+
+ // make sure that only the number with data == 1 was remove
+ int count = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ count += a.node(i).data;
+ DLIB_TEST(a.node(i).number_of_children() == 0);
+ DLIB_TEST(a.node(i).number_of_parents() == 0);
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+
+ DLIB_TEST(count == 9);
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+
+ a.add_edge(1,1);
+ DLIB_TEST(graph_contains_length_one_cycle(a) == true);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == true);
+
+ a.add_edge(1,2);
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == true);
+
+ DLIB_TEST(a.node(1).number_of_children() == 2);
+ DLIB_TEST(a.node(1).number_of_parents() == 1);
+ DLIB_TEST_MSG(a.node(1).parent(0).index() == 1,"");
+
+ DLIB_TEST_MSG(a.node(1).child(0).index() + a.node(1).child(1).index() == 3,"");
+ DLIB_TEST(a.node(2).number_of_children() == 0);
+ DLIB_TEST(a.node(2).number_of_parents() == 1);
+ DLIB_TEST(a.node(2).index() == 2);
+
+ int val = a.node(1).data;
+ a.remove_node(1);
+ DLIB_TEST(graph_contains_length_one_cycle(a) == false);
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+
+
+ DLIB_TEST(a.number_of_nodes() == 3);
+
+ count = 0;
+ for (int i = 0; i < 3; ++i)
+ {
+ count += a.node(i).data;
+ DLIB_TEST(a.node(i).number_of_children() == 0);
+ DLIB_TEST(a.node(i).number_of_parents() == 0);
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+ DLIB_TEST(count == 9-val);
+
+
+ val = a.add_node();
+ DLIB_TEST(val == 3);
+ DLIB_TEST(a.number_of_nodes() == 4);
+
+ for (int i = 0; i < 4; ++i)
+ {
+ a.node(i).data = i;
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+
+ for (int i = 0; i < 4; ++i)
+ {
+ DLIB_TEST(a.node(i).data == i);
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+
+ a.add_edge(0, 1);
+ a.add_edge(0, 2);
+ DLIB_TEST(graph_is_connected(a) == false);
+ a.add_edge(1, 3);
+ DLIB_TEST(graph_is_connected(a) == true);
+ a.add_edge(2, 3);
+ DLIB_TEST(graph_is_connected(a) == true);
+ DLIB_TEST(graph_contains_length_one_cycle(a) == false);
+
+ DLIB_TEST(a.has_edge(0, 1));
+ DLIB_TEST(a.has_edge(0, 2));
+ DLIB_TEST(a.has_edge(1, 3));
+ DLIB_TEST(a.has_edge(2, 3));
+
+ DLIB_TEST(!a.has_edge(1, 0));
+ DLIB_TEST(!a.has_edge(2, 0));
+ DLIB_TEST(!a.has_edge(3, 1));
+ DLIB_TEST(!a.has_edge(3, 2));
+
+ DLIB_TEST(a.node(0).number_of_parents() == 0);
+ DLIB_TEST(a.node(0).number_of_children() == 2);
+
+ DLIB_TEST(a.node(1).number_of_parents() == 1);
+ DLIB_TEST(a.node(1).number_of_children() == 1);
+ DLIB_TEST(a.node(1).child(0).index() == 3);
+ DLIB_TEST(a.node(1).parent(0).index() == 0);
+
+ DLIB_TEST(a.node(2).number_of_parents() == 1);
+ DLIB_TEST(a.node(2).number_of_children() == 1);
+ DLIB_TEST(a.node(2).child(0).index() == 3);
+ DLIB_TEST(a.node(2).parent(0).index() == 0);
+
+ DLIB_TEST(a.node(3).number_of_parents() == 2);
+ DLIB_TEST(a.node(3).number_of_children() == 0);
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+
+ a.remove_edge(0,1);
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+
+ DLIB_TEST(!a.has_edge(0, 1));
+ DLIB_TEST(a.has_edge(0, 2));
+ DLIB_TEST(a.has_edge(1, 3));
+ DLIB_TEST(a.has_edge(2, 3));
+
+ DLIB_TEST(!a.has_edge(1, 0));
+ DLIB_TEST(!a.has_edge(2, 0));
+ DLIB_TEST(!a.has_edge(3, 1));
+ DLIB_TEST(!a.has_edge(3, 2));
+
+
+ DLIB_TEST(a.node(0).number_of_parents() == 0);
+ DLIB_TEST(a.node(0).number_of_children() == 1);
+
+ DLIB_TEST(a.node(1).number_of_parents() == 0);
+ DLIB_TEST(a.node(1).number_of_children() == 1);
+ DLIB_TEST(a.node(1).child(0).index() == 3);
+
+ DLIB_TEST(a.node(2).number_of_parents() == 1);
+ DLIB_TEST(a.node(2).number_of_children() == 1);
+ DLIB_TEST(a.node(2).child(0).index() == 3);
+ DLIB_TEST(a.node(2).parent(0).index() == 0);
+
+ DLIB_TEST(a.node(3).number_of_parents() == 2);
+ DLIB_TEST(a.node(3).number_of_children() == 0);
+
+ for (int i = 0; i < 4; ++i)
+ {
+ DLIB_TEST(a.node(i).data == i);
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+
+
+
+ swap(a,b);
+
+ DLIB_TEST(a.number_of_nodes() == 0);
+ DLIB_TEST(b.number_of_nodes() == 4);
+ DLIB_TEST(b.node(0).number_of_parents() == 0);
+ DLIB_TEST(b.node(0).number_of_children() == 1);
+
+ DLIB_TEST(b.node(1).number_of_parents() == 0);
+ DLIB_TEST(b.node(1).number_of_children() == 1);
+ DLIB_TEST(b.node(1).child(0).index() == 3);
+
+ DLIB_TEST(b.node(2).number_of_parents() == 1);
+ DLIB_TEST(b.node(2).number_of_children() == 1);
+ DLIB_TEST(b.node(2).child(0).index() == 3);
+ DLIB_TEST(b.node(2).parent(0).index() == 0);
+
+ DLIB_TEST(b.node(3).number_of_parents() == 2);
+ DLIB_TEST(b.node(3).number_of_children() == 0);
+ b.node(0).child_edge(0) = static_cast<unsigned short>(b.node(0).child(0).index()+1);
+ b.node(1).child_edge(0) = static_cast<unsigned short>(b.node(1).child(0).index()+1);
+ b.node(2).child_edge(0) = static_cast<unsigned short>(b.node(2).child(0).index()+1);
+
+ DLIB_TEST_MSG(b.node(0).child_edge(0) == b.node(0).child(0).index()+1,
+ b.node(0).child_edge(0) << " " << b.node(0).child(0).index()+1);
+ DLIB_TEST_MSG(b.node(1).child_edge(0) == b.node(1).child(0).index()+1,
+ b.node(1).child_edge(0) << " " << b.node(1).child(0).index()+1);
+ DLIB_TEST_MSG(b.node(2).child_edge(0) == b.node(2).child(0).index()+1,
+ b.node(2).child_edge(0) << " " << b.node(2).child(0).index()+1);
+
+ DLIB_TEST_MSG(b.node(2).parent_edge(0) == 2+1,
+ b.node(2).parent_edge(0) << " " << 2+1);
+ DLIB_TEST_MSG(b.node(3).parent_edge(0) == 3+1,
+ b.node(3).parent_edge(0) << " " << 3+1);
+ DLIB_TEST_MSG(b.node(3).parent_edge(1) == 3+1,
+ b.node(3).parent_edge(1) << " " << 3+1);
+
+ ostringstream sout;
+
+ serialize(b, sout);
+
+ istringstream sin(sout.str());
+
+ a.set_number_of_nodes(20);
+ DLIB_TEST(a.number_of_nodes() == 20);
+ deserialize(a, sin);
+ DLIB_TEST(a.number_of_nodes() == 4);
+
+ DLIB_TEST(!a.has_edge(0, 1));
+ DLIB_TEST(a.has_edge(0, 2));
+ DLIB_TEST(a.has_edge(1, 3));
+ DLIB_TEST(a.has_edge(2, 3));
+
+ DLIB_TEST(!a.has_edge(1, 0));
+ DLIB_TEST(!a.has_edge(2, 0));
+ DLIB_TEST(!a.has_edge(3, 1));
+ DLIB_TEST(!a.has_edge(3, 2));
+
+ DLIB_TEST_MSG(a.node(0).child_edge(0) == a.node(0).child(0).index()+1,
+ a.node(0).child_edge(0) << " " << a.node(0).child(0).index()+1);
+ DLIB_TEST_MSG(a.node(1).child_edge(0) == a.node(1).child(0).index()+1,
+ a.node(1).child_edge(0) << " " << a.node(1).child(0).index()+1);
+ DLIB_TEST_MSG(a.node(2).child_edge(0) == a.node(2).child(0).index()+1,
+ a.node(2).child_edge(0) << " " << a.node(2).child(0).index()+1);
+ DLIB_TEST_MSG(a.node(2).parent_edge(0) == 2+1,
+ a.node(2).parent_edge(0) << " " << 2+1);
+ DLIB_TEST_MSG(a.node(3).parent_edge(0) == 3+1,
+ a.node(3).parent_edge(0) << " " << 3+1);
+ DLIB_TEST_MSG(a.node(3).parent_edge(1) == 3+1,
+ a.node(3).parent_edge(1) << " " << 3+1);
+
+
+
+ for (int i = 0; i < 4; ++i)
+ {
+ DLIB_TEST(a.node(i).data == i);
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+
+
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+
+ DLIB_TEST(b.number_of_nodes() == 4);
+ DLIB_TEST(b.node(0).number_of_parents() == 0);
+ DLIB_TEST(b.node(0).number_of_children() == 1);
+
+ DLIB_TEST(b.node(1).number_of_parents() == 0);
+ DLIB_TEST(b.node(1).number_of_children() == 1);
+ DLIB_TEST(b.node(1).child(0).index() == 3);
+
+ DLIB_TEST(b.node(2).number_of_parents() == 1);
+ DLIB_TEST(b.node(2).number_of_children() == 1);
+ DLIB_TEST(b.node(2).child(0).index() == 3);
+ DLIB_TEST(b.node(2).parent(0).index() == 0);
+
+ DLIB_TEST(b.node(3).number_of_parents() == 2);
+ DLIB_TEST(b.node(3).number_of_children() == 0);
+
+
+ DLIB_TEST(a.number_of_nodes() == 4);
+ DLIB_TEST(a.node(0).number_of_parents() == 0);
+ DLIB_TEST(a.node(0).number_of_children() == 1);
+
+ DLIB_TEST(a.node(1).number_of_parents() == 0);
+ DLIB_TEST(a.node(1).number_of_children() == 1);
+ DLIB_TEST(a.node(1).child(0).index() == 3);
+
+ DLIB_TEST(a.node(2).number_of_parents() == 1);
+ DLIB_TEST(a.node(2).number_of_children() == 1);
+ DLIB_TEST(a.node(2).child(0).index() == 3);
+ DLIB_TEST(a.node(2).parent(0).index() == 0);
+
+ DLIB_TEST(a.node(3).number_of_parents() == 2);
+ DLIB_TEST(a.node(3).number_of_children() == 0);
+
+ DLIB_TEST(a.number_of_nodes() == 4);
+ a.clear();
+ DLIB_TEST(a.number_of_nodes() == 0);
+
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+
+ a.set_number_of_nodes(10);
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+
+ a.add_edge(0,1);
+ a.add_edge(1,2);
+ a.add_edge(1,3);
+ a.add_edge(2,4);
+ a.add_edge(3,4);
+ a.add_edge(4,5);
+ a.add_edge(5,1);
+
+ DLIB_TEST(graph_contains_directed_cycle(a) == true);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+
+ a.remove_edge(5,1);
+
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+ a.add_edge(7,8);
+ DLIB_TEST(graph_contains_directed_cycle(a) == false);
+ a.add_edge(8,7);
+ DLIB_TEST(graph_contains_directed_cycle(a) == true);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+
+
+ a.clear();
+ /*
+ Make a graph that looks like:
+ 0 1
+ \ /
+ 2
+ |
+ 3
+ */
+ a.set_number_of_nodes(4);
+ a.add_edge(0,2);
+ a.add_edge(1,2);
+ a.add_edge(2,3);
+ for (unsigned long i = 0; i < 4; ++i)
+ a.node(i).data = i;
+
+ graph<int>::kernel_1a_c g;
+ create_moral_graph(a,g);
+
+ graph<dlib::set<unsigned long>::compare_1b_c, dlib::set<unsigned long>::compare_1a_c>::kernel_1a_c join_tree;
+ dlib::set<dlib::set<unsigned long>::compare_1b_c>::kernel_1b_c sos;
+
+ create_join_tree(g, join_tree);
+ DLIB_TEST(is_join_tree(g, join_tree));
+ DLIB_TEST(join_tree.number_of_nodes() == 2);
+ DLIB_TEST(graph_contains_undirected_cycle(join_tree) == false);
+ DLIB_TEST(graph_is_connected(join_tree) == true);
+
+ unsigned long temp;
+ triangulate_graph_and_find_cliques(g,sos);
+
+ temp = 2; s.add(temp);
+ temp = 3; s.add(temp);
+ DLIB_TEST(sos.is_member(s));
+ s.clear();
+ temp = 0; s.add(temp);
+ temp = 1; s.add(temp);
+ temp = 2; s.add(temp);
+ DLIB_TEST(sos.is_member(s));
+ DLIB_TEST(sos.size() == 2);
+ DLIB_TEST(sos.is_member(join_tree.node(0).data));
+ DLIB_TEST(sos.is_member(join_tree.node(1).data));
+
+
+ s.clear();
+ temp = 0; s.add(temp);
+ DLIB_TEST(is_clique(g,s) == true);
+ DLIB_TEST(is_maximal_clique(g,s) == false);
+ temp = 3; s.add(temp);
+ DLIB_TEST(is_clique(g,s) == false);
+ s.destroy(3);
+ DLIB_TEST(is_clique(g,s) == true);
+ temp = 2; s.add(temp);
+ DLIB_TEST(is_clique(g,s) == true);
+ DLIB_TEST(is_maximal_clique(g,s) == false);
+ temp = 1; s.add(temp);
+ DLIB_TEST(is_clique(g,s) == true);
+ DLIB_TEST(is_maximal_clique(g,s) == true);
+ s.clear();
+ DLIB_TEST(is_clique(g,s) == true);
+ temp = 3; s.add(temp);
+ DLIB_TEST(is_clique(g,s) == true);
+ temp = 2; s.add(temp);
+ DLIB_TEST(is_clique(g,s) == true);
+ DLIB_TEST(is_maximal_clique(g,s) == true);
+
+
+ DLIB_TEST(a.number_of_nodes() == 4);
+ DLIB_TEST(g.number_of_nodes() == 4);
+ for (unsigned long i = 0; i < 4; ++i)
+ DLIB_TEST( a.node(i).data == (int)i);
+ DLIB_TEST(g.has_edge(0,1));
+ DLIB_TEST(g.has_edge(0,2));
+ DLIB_TEST(g.has_edge(1,2));
+ DLIB_TEST(g.has_edge(3,2));
+ DLIB_TEST(g.has_edge(0,3) == false);
+ DLIB_TEST(g.has_edge(1,3) == false);
+
+ }
+
+
+ void test_copy()
+ {
+ {
+ directed_graph<int,int>::kernel_1a_c a,b;
+
+ a.set_number_of_nodes(3);
+ a.node(0).data = 1;
+ a.node(1).data = 2;
+ a.node(2).data = 3;
+ a.add_edge(0,1);
+ a.add_edge(1,0);
+ a.add_edge(0,2);
+ edge(a,0,1) = 4;
+ edge(a,1,0) = 3;
+ edge(a,0,2) = 5;
+
+ a.add_edge(0,0);
+ edge(a,0,0) = 9;
+ copy_graph(a, b);
+
+ DLIB_TEST(b.number_of_nodes() == 3);
+ DLIB_TEST(b.node(0).data == 1);
+ DLIB_TEST(b.node(1).data == 2);
+ DLIB_TEST(b.node(2).data == 3);
+ DLIB_TEST(edge(b,0,1) == 4);
+ DLIB_TEST(edge(b,1,0) == 3);
+ DLIB_TEST(edge(b,0,2) == 5);
+ DLIB_TEST(edge(b,0,0) == 9);
+ }
+ {
+ directed_graph<int,int>::kernel_1a_c a,b;
+
+ a.set_number_of_nodes(4);
+ a.node(0).data = 1;
+ a.node(1).data = 2;
+ a.node(2).data = 3;
+ a.node(3).data = 8;
+ a.add_edge(0,1);
+ a.add_edge(0,2);
+ a.add_edge(2,3);
+ a.add_edge(3,2);
+ edge(a,0,1) = 4;
+ edge(a,0,2) = 5;
+ edge(a,2,3) = 6;
+ edge(a,3,2) = 3;
+
+ copy_graph(a, b);
+
+ DLIB_TEST(b.number_of_nodes() == 4);
+ DLIB_TEST(b.node(0).data == 1);
+ DLIB_TEST(b.node(1).data == 2);
+ DLIB_TEST(b.node(2).data == 3);
+ DLIB_TEST(b.node(3).data == 8);
+ DLIB_TEST(edge(b,0,1) == 4);
+ DLIB_TEST(edge(b,0,2) == 5);
+ DLIB_TEST(edge(b,2,3) == 6);
+ DLIB_TEST(edge(b,3,2) == 3);
+ }
+ }
+
+
+
+ class directed_graph_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a test for the directed_graph object. When it is constructed
+ it adds itself into the testing framework. The command line switch is
+ specified as test_directed_graph by passing that string to the tester constructor.
+ !*/
+ public:
+ directed_graph_tester (
+ ) :
+ tester ("test_directed_graph",
+ "Runs tests on the directed_graph component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_copy();
+
+ dlog << LINFO << "testing kernel_1a_c";
+ directed_graph_test<directed_graph<int,unsigned short>::kernel_1a_c>();
+
+ dlog << LINFO << "testing kernel_1a";
+ directed_graph_test<directed_graph<int,unsigned short>::kernel_1a>();
+ }
+ } a;
+
+
+}
+
+
diff --git a/ml/dlib/dlib/test/discriminant_pca.cpp b/ml/dlib/dlib/test/discriminant_pca.cpp
new file mode 100644
index 000000000..2a7aa61d1
--- /dev/null
+++ b/ml/dlib/dlib/test/discriminant_pca.cpp
@@ -0,0 +1,365 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm.h>
+#include <dlib/rand.h>
+#include <dlib/string.h>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.discriminant_pca");
+
+ using dlib::equal;
+
+ class discriminant_pca_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ discriminant_pca_tester (
+ ) :
+ tester (
+ "test_discriminant_pca", // the command line argument name for this test
+ "Run tests on the discriminant_pca object.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ thetime = 1407805946;// time(0);
+ }
+
+ time_t thetime;
+ dlib::rand rnd;
+
+ template <typename dpca_type>
+ void test1()
+ {
+
+ dpca_type dpca, dpca2, dpca3;
+
+ DLIB_TEST(dpca.in_vector_size() == 0);
+ DLIB_TEST(dpca.between_class_weight() == 1);
+ DLIB_TEST(dpca.within_class_weight() == 1);
+
+ // generate a bunch of 4 dimensional vectors and compute the normal PCA transformation matrix
+ // and just make sure it is a unitary matrix as it should be.
+ for (int i = 0; i < 5000; ++i)
+ {
+ dpca.add_to_total_variance(randm(4,1,rnd));
+ DLIB_TEST(dpca.in_vector_size() == 4);
+ }
+
+
+ matrix<double> mat = dpca.dpca_matrix(1);
+
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(4)));
+
+ mat = dpca.dpca_matrix(0.9);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(mat.nr())));
+
+ matrix<double> eig;
+ dpca.dpca_matrix(mat, eig, 1);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(4)));
+ // check that all eigen values are grater than 0
+ DLIB_TEST(min(eig > 0) == 1);
+ DLIB_TEST(eig.size() == mat.nr());
+ DLIB_TEST(is_col_vector(eig));
+ // check that the eigenvalues are sorted
+ double last = eig(0);
+ for (long i = 1; i < eig.size(); ++i)
+ {
+ DLIB_TEST(last >= eig(i));
+ }
+
+ {
+ matrix<double> mat = dpca.dpca_matrix_of_size(4);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(4)));
+ }
+ {
+ matrix<double> mat = dpca.dpca_matrix_of_size(3);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(3)));
+ }
+
+
+ dpca.set_within_class_weight(5);
+ dpca.set_between_class_weight(6);
+
+ DLIB_TEST(dpca.in_vector_size() == 4);
+ DLIB_TEST(dpca.within_class_weight() == 5);
+ DLIB_TEST(dpca.between_class_weight() == 6);
+
+
+ ostringstream sout;
+ serialize(dpca, sout);
+ istringstream sin(sout.str());
+ deserialize(dpca2, sin);
+
+ // now make sure the serialization worked
+ DLIB_TEST(dpca.in_vector_size() == 4);
+ DLIB_TEST(dpca.within_class_weight() == 5);
+ DLIB_TEST(dpca.between_class_weight() == 6);
+ DLIB_TEST(dpca2.in_vector_size() == 4);
+ DLIB_TEST(dpca2.within_class_weight() == 5);
+ DLIB_TEST(dpca2.between_class_weight() == 6);
+ DLIB_TEST(equal(dpca.dpca_matrix(), dpca2.dpca_matrix(), 1e-10));
+ DLIB_TEST(equal(mat, dpca2.dpca_matrix(1), 1e-10));
+ DLIB_TEST(equal(dpca.dpca_matrix(1), mat, 1e-10));
+
+ // now test swap
+ dpca2.swap(dpca3);
+ DLIB_TEST(dpca2.in_vector_size() == 0);
+ DLIB_TEST(dpca2.between_class_weight() == 1);
+ DLIB_TEST(dpca2.within_class_weight() == 1);
+
+ DLIB_TEST(dpca3.in_vector_size() == 4);
+ DLIB_TEST(dpca3.within_class_weight() == 5);
+ DLIB_TEST(dpca3.between_class_weight() == 6);
+ DLIB_TEST(equal(mat, dpca3.dpca_matrix(1), 1e-10));
+ DLIB_TEST((dpca3 + dpca3).in_vector_size() == 4);
+ DLIB_TEST((dpca3 + dpca3).within_class_weight() == 5);
+ DLIB_TEST((dpca3 + dpca3).between_class_weight() == 6);
+
+ dpca.clear();
+
+ DLIB_TEST(dpca.in_vector_size() == 0);
+ DLIB_TEST(dpca.between_class_weight() == 1);
+ DLIB_TEST(dpca.within_class_weight() == 1);
+ }
+
+ template <typename dpca_type>
+ void test2()
+ {
+ dpca_type dpca, dpca2, dpca3;
+
+ typename dpca_type::column_matrix samp1(4), samp2(4);
+
+ for (int i = 0; i < 5000; ++i)
+ {
+ dpca.add_to_total_variance(randm(4,1,rnd));
+ DLIB_TEST(dpca.in_vector_size() == 4);
+
+ // do this to subtract out the variance along the 3rd axis
+ samp1 = 0,0,0,0;
+ samp2 = 0,0,1,0;
+ dpca.add_to_within_class_variance(samp1, samp2);
+ }
+
+ matrix<double> mat;
+
+ dpca.set_within_class_weight(0);
+ mat = dpca.dpca_matrix(1);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(4)));
+ DLIB_TEST(dpca.dpca_matrix(1).nr() == 4);
+ dpca.set_within_class_weight(1000);
+ DLIB_TEST(dpca.dpca_matrix(1).nr() == 3);
+
+ // the 3rd column of the transformation matrix should be all zero since
+ // we killed all the variation long the 3rd axis
+ DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),2))) < 1e-5);
+
+ mat = dpca.dpca_matrix(1);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(3)));
+
+
+ }
+
+ template <typename dpca_type>
+ void test3()
+ {
+ dpca_type dpca, dpca2, dpca3;
+
+ typename dpca_type::column_matrix samp1(4), samp2(4);
+
+ for (int i = 0; i < 5000; ++i)
+ {
+ dpca.add_to_total_variance(randm(4,1,rnd));
+ DLIB_TEST(dpca.in_vector_size() == 4);
+
+ // do this to subtract out the variance along the 3rd axis
+ samp1 = 0,0,0,0;
+ samp2 = 0,0,1,0;
+ dpca.add_to_within_class_variance(samp1, samp2);
+
+ // do this to subtract out the variance along the 1st axis
+ samp1 = 0,0,0,0;
+ samp2 = 1,0,0,0;
+ dpca.add_to_within_class_variance(samp1, samp2);
+ }
+
+ matrix<double> mat;
+
+ dpca.set_within_class_weight(0);
+ mat = dpca.dpca_matrix(1);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(4)));
+ DLIB_TEST(dpca.dpca_matrix(1).nr() == 4);
+ dpca.set_within_class_weight(10000);
+ DLIB_TEST(dpca.dpca_matrix(1).nr() == 2);
+
+ // the 1st and 3rd columns of the transformation matrix should be all zero since
+ // we killed all the variation long the 1st and 3rd axes
+ DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),2))) < 1e-5);
+ DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),0))) < 1e-5);
+
+ mat = dpca.dpca_matrix(1);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(2)));
+
+
+ }
+
+ template <typename dpca_type>
+ void test4()
+ {
+ dpca_type dpca, dpca2, dpca3;
+
+ dpca_type add_dpca1, add_dpca2, add_dpca3, add_dpca4, sum_dpca;
+
+ typename dpca_type::column_matrix samp1(4), samp2(4), samp;
+
+ for (int i = 0; i < 5000; ++i)
+ {
+ samp = randm(4,1,rnd);
+ dpca.add_to_total_variance(samp);
+ add_dpca4.add_to_total_variance(samp);
+ DLIB_TEST(dpca.in_vector_size() == 4);
+
+ // do this to subtract out the variance along the 3rd axis
+ samp1 = 0,0,0,0;
+ samp2 = 0,0,1,0;
+ dpca.add_to_within_class_variance(samp1, samp2);
+ add_dpca1.add_to_within_class_variance(samp1, samp2);
+
+ // do this to subtract out the variance along the 1st axis
+ samp1 = 0,0,0,0;
+ samp2 = 1,0,0,0;
+ dpca.add_to_within_class_variance(samp1, samp2);
+ add_dpca2.add_to_within_class_variance(samp1, samp2);
+
+ // do this to add the variance along the 3rd axis back in
+ samp1 = 0,0,0,0;
+ samp2 = 0,0,1,0;
+ dpca.add_to_between_class_variance(samp1, samp2);
+ add_dpca3.add_to_between_class_variance(samp1, samp2);
+ }
+
+ matrix<double> mat, mat2;
+
+ sum_dpca += dpca_type() + dpca_type() + add_dpca1 + dpca_type() + add_dpca2 + add_dpca3 + add_dpca4;
+ dpca.set_within_class_weight(0);
+ dpca.set_between_class_weight(0);
+ sum_dpca.set_within_class_weight(0);
+ sum_dpca.set_between_class_weight(0);
+ mat = dpca.dpca_matrix(1);
+ DLIB_TEST(equal(mat, sum_dpca.dpca_matrix(1), 1e-10));
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(4)));
+ DLIB_TEST(dpca.dpca_matrix(1).nr() == 4);
+ dpca.set_within_class_weight(10000);
+ sum_dpca.set_within_class_weight(10000);
+ DLIB_TEST(dpca.dpca_matrix(1).nr() == 2);
+
+ // the 1st and 3rd columns of the transformation matrix should be all zero since
+ // we killed all the variation long the 1st and 3rd axes
+ DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),2))) < 1e-4);
+ DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),0))) < 1e-4);
+
+ mat = dpca.dpca_matrix(1);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(2)));
+ DLIB_TEST_MSG(equal(mat, mat2=sum_dpca.dpca_matrix(1), 1e-9), max(abs(mat - mat2)));
+
+
+ // now add the variance back in using the between class weight
+ dpca.set_within_class_weight(0);
+ dpca.set_between_class_weight(1);
+ mat = dpca.dpca_matrix(1);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(4)));
+ DLIB_TEST(dpca.dpca_matrix(1).nr() == 4);
+ dpca.set_within_class_weight (10000);
+ dpca.set_between_class_weight(100000);
+ sum_dpca.set_within_class_weight (10000);
+ sum_dpca.set_between_class_weight(100000);
+ DLIB_TEST(dpca.dpca_matrix(1).nr() == 3);
+
+ // the first column should be all zeros
+ DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),0))) < 1e-5);
+
+ mat = dpca.dpca_matrix(1);
+ DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(3)));
+ DLIB_TEST(equal(mat, sum_dpca.dpca_matrix(1)));
+
+
+ }
+
+ template <typename dpca_type>
+ void test5()
+ {
+ dpca_type dpca, dpca2;
+ typename dpca_type::column_matrix samp1(4), samp2(4);
+
+ samp1 = 0,0,0,0;
+ samp2 = 0,0,1,0;
+
+ for (int i = 0; i < 5000; ++i)
+ {
+ dpca.add_to_between_class_variance(samp1, samp2);
+ dpca2.add_to_total_variance(samp1);
+ dpca2.add_to_total_variance(samp2);
+ }
+
+ matrix<double> mat, eig;
+ dpca.dpca_matrix(mat, eig, 1);
+
+ // make sure the eigenvalues come out the way they should for this simple data set
+ DLIB_TEST(eig.size() == 1);
+ DLIB_TEST_MSG(abs(eig(0) - 1) < 1e-10, abs(eig(0) - 1));
+
+ dpca2.dpca_matrix(mat, eig, 1);
+
+ // make sure the eigenvalues come out the way they should for this simple data set
+ DLIB_TEST(eig.size() == 1);
+ DLIB_TEST(abs(eig(0) - 0.25) < 1e-10);
+
+ }
+
+ void perform_test (
+ )
+ {
+ ++thetime;
+ typedef matrix<double,0,1> sample_type;
+ typedef discriminant_pca<sample_type> dpca_type;
+
+ dlog << LINFO << "time seed: " << thetime;
+ rnd.set_seed(cast_to_string(thetime));
+
+ test5<dpca_type>();
+
+ for (int i = 0; i < 10; ++i)
+ {
+ print_spinner();
+ test1<dpca_type>();
+ print_spinner();
+ test2<dpca_type>();
+ print_spinner();
+ test3<dpca_type>();
+ print_spinner();
+ test4<dpca_type>();
+ }
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ discriminant_pca_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/disjoint_subsets.cpp b/ml/dlib/dlib/test/disjoint_subsets.cpp
new file mode 100644
index 000000000..2545219cd
--- /dev/null
+++ b/ml/dlib/dlib/test/disjoint_subsets.cpp
@@ -0,0 +1,102 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/disjoint_subsets.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.disjoint_subsets");
+
+ void test_disjoint_subset()
+ {
+ print_spinner();
+ disjoint_subsets s;
+
+ DLIB_TEST(s.size() == 0);
+
+ s.set_size(5);
+ DLIB_TEST(s.size() == 5);
+
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.find_set(1) == 1);
+ DLIB_TEST(s.find_set(2) == 2);
+ DLIB_TEST(s.find_set(3) == 3);
+ DLIB_TEST(s.find_set(4) == 4);
+
+ unsigned long id = s.merge_sets(1,3);
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.find_set(1) == id);
+ DLIB_TEST(s.find_set(2) == 2);
+ DLIB_TEST(s.find_set(3) == id);
+ DLIB_TEST(s.find_set(4) == 4);
+
+ id = s.merge_sets(s.find_set(1),4);
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.find_set(1) == id);
+ DLIB_TEST(s.find_set(2) == 2);
+ DLIB_TEST(s.find_set(3) == id);
+ DLIB_TEST(s.find_set(4) == id);
+
+ unsigned long id2 = s.merge_sets(0,2);
+ DLIB_TEST(s.find_set(0) == id2);
+ DLIB_TEST(s.find_set(1) == id);
+ DLIB_TEST(s.find_set(2) == id2);
+ DLIB_TEST(s.find_set(3) == id);
+ DLIB_TEST(s.find_set(4) == id);
+
+ id = s.merge_sets(s.find_set(1),s.find_set(0));
+ DLIB_TEST(s.find_set(0) == id);
+ DLIB_TEST(s.find_set(1) == id);
+ DLIB_TEST(s.find_set(2) == id);
+ DLIB_TEST(s.find_set(3) == id);
+ DLIB_TEST(s.find_set(4) == id);
+
+ DLIB_TEST(s.size() == 5);
+ s.set_size(1);
+ DLIB_TEST(s.size() == 1);
+ DLIB_TEST(s.find_set(0) == 0);
+ s.set_size(2);
+ DLIB_TEST(s.size() == 2);
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.find_set(1) == 1);
+ id = s.merge_sets(0,1);
+ DLIB_TEST(s.size() == 2);
+ DLIB_TEST(id == s.find_set(0));
+ DLIB_TEST(id == s.find_set(1));
+ DLIB_TEST(s.size() == 2);
+ s.clear();
+ DLIB_TEST(s.size() == 0);
+
+ }
+
+
+ class tester_disjoint_subsets : public tester
+ {
+ public:
+ tester_disjoint_subsets (
+ ) :
+ tester ("test_disjoint_subsets",
+ "Runs tests on the disjoint_subsets component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_disjoint_subset();
+ }
+ } a;
+
+
+}
diff --git a/ml/dlib/dlib/test/disjoint_subsets_sized.cpp b/ml/dlib/dlib/test/disjoint_subsets_sized.cpp
new file mode 100644
index 000000000..57ced68e6
--- /dev/null
+++ b/ml/dlib/dlib/test/disjoint_subsets_sized.cpp
@@ -0,0 +1,143 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/disjoint_subsets.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.disjoint_subsets_sized");
+
+ void test_disjoint_subsets_sized()
+ {
+ print_spinner();
+ disjoint_subsets_sized s;
+
+ DLIB_TEST(s.size() == 0);
+ DLIB_TEST(s.get_number_of_sets() == 0);
+
+ s.set_size(5);
+ DLIB_TEST(s.size() == 5);
+ DLIB_TEST(s.get_number_of_sets() == 5);
+
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.find_set(1) == 1);
+ DLIB_TEST(s.find_set(2) == 2);
+ DLIB_TEST(s.find_set(3) == 3);
+ DLIB_TEST(s.find_set(4) == 4);
+
+ DLIB_TEST(s.get_size_of_set(0) == 1);
+ DLIB_TEST(s.get_size_of_set(1) == 1);
+ DLIB_TEST(s.get_size_of_set(2) == 1);
+ DLIB_TEST(s.get_size_of_set(3) == 1);
+ DLIB_TEST(s.get_size_of_set(4) == 1);
+
+ unsigned long id = s.merge_sets(1,3);
+ DLIB_TEST(s.get_number_of_sets() == 4);
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.find_set(1) == id);
+ DLIB_TEST(s.find_set(2) == 2);
+ DLIB_TEST(s.find_set(3) == id);
+ DLIB_TEST(s.find_set(4) == 4);
+ DLIB_TEST(s.get_size_of_set(0) == 1);
+ DLIB_TEST(s.get_size_of_set(s.find_set(1)) == 2);
+ DLIB_TEST(s.get_size_of_set(2) == 1);
+ DLIB_TEST(s.get_size_of_set(s.find_set(3)) == 2);
+ DLIB_TEST(s.get_size_of_set(4) == 1);
+
+ id = s.merge_sets(s.find_set(1),4);
+ DLIB_TEST(s.get_number_of_sets() == 3);
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.find_set(1) == id);
+ DLIB_TEST(s.find_set(2) == 2);
+ DLIB_TEST(s.find_set(3) == id);
+ DLIB_TEST(s.find_set(4) == id);
+ DLIB_TEST(s.get_size_of_set(0) == 1);
+ DLIB_TEST(s.get_size_of_set(s.find_set(1)) == 3);
+ DLIB_TEST(s.get_size_of_set(2) == 1);
+ DLIB_TEST(s.get_size_of_set(s.find_set(3)) == 3);
+ DLIB_TEST(s.get_size_of_set(s.find_set(4)) == 3);
+
+ unsigned long id2 = s.merge_sets(0,2);
+ DLIB_TEST(s.get_number_of_sets() == 2);
+ DLIB_TEST(s.find_set(0) == id2);
+ DLIB_TEST(s.find_set(1) == id);
+ DLIB_TEST(s.find_set(2) == id2);
+ DLIB_TEST(s.find_set(3) == id);
+ DLIB_TEST(s.find_set(4) == id);
+ DLIB_TEST(s.get_size_of_set(s.find_set(0)) == 2);
+ DLIB_TEST(s.get_size_of_set(s.find_set(1)) == 3);
+ DLIB_TEST(s.get_size_of_set(s.find_set(2)) == 2);
+ DLIB_TEST(s.get_size_of_set(s.find_set(3)) == 3);
+ DLIB_TEST(s.get_size_of_set(s.find_set(4)) == 3);
+
+ id = s.merge_sets(s.find_set(1),s.find_set(0));
+ DLIB_TEST(s.get_number_of_sets() == 1);
+ DLIB_TEST(s.find_set(0) == id);
+ DLIB_TEST(s.find_set(1) == id);
+ DLIB_TEST(s.find_set(2) == id);
+ DLIB_TEST(s.find_set(3) == id);
+ DLIB_TEST(s.find_set(4) == id);
+ DLIB_TEST(s.get_size_of_set(s.find_set(0)) == 5);
+ DLIB_TEST(s.get_size_of_set(s.find_set(1)) == 5);
+ DLIB_TEST(s.get_size_of_set(s.find_set(2)) == 5);
+ DLIB_TEST(s.get_size_of_set(s.find_set(3)) == 5);
+ DLIB_TEST(s.get_size_of_set(s.find_set(4)) == 5);
+
+ DLIB_TEST(s.size() == 5);
+ s.set_size(1);
+ DLIB_TEST(s.size() == 1);
+ DLIB_TEST(s.get_number_of_sets() == 1);
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.get_size_of_set(0) == 1);
+ s.set_size(2);
+ DLIB_TEST(s.size() == 2);
+ DLIB_TEST(s.get_number_of_sets() == 2);
+ DLIB_TEST(s.find_set(0) == 0);
+ DLIB_TEST(s.find_set(1) == 1);
+ DLIB_TEST(s.get_size_of_set(0) == 1);
+ DLIB_TEST(s.get_size_of_set(1) == 1);
+ id = s.merge_sets(0,1);
+ DLIB_TEST(s.size() == 2);
+ DLIB_TEST(s.get_number_of_sets() == 1);
+ DLIB_TEST(id == s.find_set(0));
+ DLIB_TEST(id == s.find_set(1));
+ DLIB_TEST(s.get_size_of_set(s.find_set(0)) == 2);
+ DLIB_TEST(s.get_size_of_set(s.find_set(1)) == 2);
+ DLIB_TEST(s.size() == 2);
+ s.clear();
+ DLIB_TEST(s.size() == 0);
+ DLIB_TEST(s.get_number_of_sets() == 0);
+
+ }
+
+
+ class tester_disjoint_subsets_sized : public tester
+ {
+ public:
+ tester_disjoint_subsets_sized (
+ ) :
+ tester ("test_disjoint_subsets_sized",
+ "Runs tests on the disjoint_subsets_sized component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_disjoint_subsets_sized();
+ }
+ } a;
+
+
+}
diff --git a/ml/dlib/dlib/test/dnn.cpp b/ml/dlib/dlib/test/dnn.cpp
new file mode 100644
index 000000000..9d3258b70
--- /dev/null
+++ b/ml/dlib/dlib/test/dnn.cpp
@@ -0,0 +1,3261 @@
+// Copyright (C) 2015 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include <random>
+#include <numeric>
+#include "../dnn.h"
+
+#include "tester.h"
+
+#ifndef __INTELLISENSE__
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.dnn");
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ float compare_gradients (
+ const tensor& t,
+ T grad
+ )
+ {
+ float max_error = 0;
+ auto p = t.host();
+ for (size_t i = 0; i < t.size(); ++i)
+ {
+ max_error = std::max(max_error, std::abs(p[i]-grad(i)));
+ }
+ return max_error;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_tanh()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor src, dest, gradient_input;
+ src = matrix_cast<float>(gaussian_randm(5,5, 0));
+ dest = matrix_cast<float>(gaussian_randm(5,5, 1));
+ gradient_input = matrix_cast<float>(gaussian_randm(5,5, 2));
+
+
+
+ auto grad_src = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = src.host()[idx];
+ src.host()[idx] += eps;
+ tanh(dest, src);
+ float result = dot(gradient_input, dest);
+ src.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+
+ resizable_tensor src_grad;
+ src_grad.copy_size(src);
+ src_grad = 0;
+
+ tanh(dest, src);
+ tanh_gradient(src_grad, dest, gradient_input);
+
+ auto grad_error = compare_gradients(src_grad, grad_src);
+ dlog << LINFO << "src error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+ }
+
+ void test_sigmoid()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor src, dest, gradient_input;
+ src = matrix_cast<float>(gaussian_randm(5,5, 0));
+ dest = matrix_cast<float>(gaussian_randm(5,5, 1));
+ gradient_input = matrix_cast<float>(gaussian_randm(5,5, 2));
+
+
+
+ auto grad_src = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = src.host()[idx];
+ src.host()[idx] += eps;
+ sigmoid(dest, src);
+ float result = dot(gradient_input, dest);
+ src.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+
+ resizable_tensor src_grad;
+ src_grad.copy_size(src);
+ src_grad = 0;
+
+ sigmoid(dest, src);
+ sigmoid_gradient(src_grad, dest, gradient_input);
+
+ auto grad_error = compare_gradients(src_grad, grad_src);
+ dlog << LINFO << "src error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+ }
+
+ void test_softmax()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ const long nr = 3;
+ const long nc = 3;
+ resizable_tensor src(5,5,nr,nr), dest(5,5,nr,nc), gradient_input(5,5,nr,nc);
+ tt::tensor_rand rnd;
+ rnd.fill_uniform(src);
+ rnd.fill_uniform(dest);
+ // fill like this as a test of the assignment operator.
+ gradient_input = matrix_cast<float>(gaussian_randm(5,5*nr*nc, 2));
+
+
+
+ auto grad_src = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = src.host()[idx];
+ src.host()[idx] += eps;
+ tt::softmax(dest, src);
+ float result = dot(gradient_input, dest);
+ src.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+
+ resizable_tensor src_grad;
+ src_grad.copy_size(src);
+ src_grad = 0;
+
+ tt::softmax(dest, src);
+ softmax_gradient(src_grad, dest, gradient_input);
+
+ auto grad_error = compare_gradients(src_grad, grad_src);
+ dlog << LINFO << "src error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+
+#ifdef DLIB_USE_CUDA
+ resizable_tensor src1 = src;
+ resizable_tensor src2 = src;
+ resizable_tensor dest1, dest2;
+ dest1.copy_size(src);
+ dest2.copy_size(src);
+ cuda::softmax_all(dest1, src1);
+ cpu::softmax_all(dest2, src2);
+ DLIB_TEST_MSG(max(abs(mat(dest1)-mat(dest2))) < 1e-5, max(abs(mat(dest1)-mat(dest2))));
+#endif
+ }
+
+ void test_softmax_all()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ const long nr = 3;
+ const long nc = 3;
+ resizable_tensor src(5,5,nr,nr), dest(5,5,nr,nc), gradient_input(5,5,nr,nc);
+ tt::tensor_rand rnd;
+ rnd.fill_uniform(src);
+ rnd.fill_uniform(dest);
+ // fill like this as a test of the assignment operator.
+ gradient_input = matrix_cast<float>(gaussian_randm(5,5*nr*nc, 2));
+
+
+
+ auto grad_src = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = src.host()[idx];
+ src.host()[idx] += eps;
+ tt::softmax_all(dest, src);
+ float result = dot(gradient_input, dest);
+ src.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+
+ resizable_tensor src_grad;
+ src_grad.copy_size(src);
+ src_grad = 0;
+
+ tt::softmax_all(dest, src);
+ softmax_all_gradient(src_grad, dest, gradient_input);
+
+ auto grad_error = compare_gradients(src_grad, grad_src);
+ dlog << LINFO << "src error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+
+#ifdef DLIB_USE_CUDA
+ resizable_tensor src1 = src;
+ resizable_tensor src2 = src;
+ resizable_tensor dest1, dest2;
+ dest1.copy_size(src);
+ dest2.copy_size(src);
+ cuda::softmax_all(dest1, src1);
+ cpu::softmax_all(dest2, src2);
+ DLIB_TEST_MSG(max(abs(mat(dest1)-mat(dest2))) < 1e-5, max(abs(mat(dest1)-mat(dest2))));
+#endif
+ }
+
+ void test_batch_normalize()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor src, gamma, beta, dest, dest2, dest3, means, vars, gradient_input;
+ src = matrix_cast<float>(gaussian_randm(5,5, 0));
+ gamma = matrix_cast<float>(gaussian_randm(1,5, 1));
+ beta = matrix_cast<float>(gaussian_randm(1,5, 2));
+ gradient_input = matrix_cast<float>(gaussian_randm(5,5, 3));
+
+ gamma = 1;
+ beta = 0;
+
+ resizable_tensor running_means;
+ resizable_tensor running_variances;
+ batch_normalize(DEFAULT_BATCH_NORM_EPS,dest, means, vars, 1, running_means, running_variances, src, gamma, beta);
+ const double scale = (src.num_samples())/(src.num_samples()-1.0);
+ // Turn back into biased variance estimate because that's how batch_normalize() works, so if we want to match it this is necessary.
+ running_variances = mat(running_variances)/scale;
+ batch_normalize_inference(DEFAULT_BATCH_NORM_EPS,dest2, src, gamma, beta, running_means, running_variances);
+ DLIB_TEST_MSG(max(abs(mat(dest2)-mat(dest))) < 1e-5, max(abs(mat(dest2)-mat(dest))));
+ cpu::batch_normalize_inference(DEFAULT_BATCH_NORM_EPS,dest3, src, gamma, beta, running_means, running_variances);
+ DLIB_TEST_MSG(max(abs(mat(dest3)-mat(dest))) < 1e-5, max(abs(mat(dest3)-mat(dest))));
+
+
+ auto grad_src = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = src.host()[idx];
+ src.host()[idx] += eps;
+ batch_normalize(DEFAULT_BATCH_NORM_EPS,dest, means, vars, 1, running_means, running_variances, src, gamma, beta);
+ float result = dot(gradient_input, dest);
+ src.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+ auto grad_gamma = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = gamma.host()[idx];
+ gamma.host()[idx] += eps;
+ batch_normalize(DEFAULT_BATCH_NORM_EPS,dest, means, vars, 1, running_means, running_variances, src, gamma, beta);
+ float result = dot(gradient_input, dest);
+ gamma.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+ auto grad_beta = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = beta.host()[idx];
+ beta.host()[idx] += eps;
+ batch_normalize(DEFAULT_BATCH_NORM_EPS,dest, means, vars, 1, running_means, running_variances, src, gamma, beta);
+ float result = dot(gradient_input, dest);
+ beta.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+
+ resizable_tensor src_grad, gamma_grad, beta_grad;
+ src_grad.copy_size(src);
+ gamma_grad.copy_size(gamma);
+ beta_grad.copy_size(beta);
+ src_grad = 0;
+ gamma_grad = 8;
+ beta_grad = 8;
+
+ batch_normalize_gradient(DEFAULT_BATCH_NORM_EPS,gradient_input, means, vars, src, gamma, src_grad, gamma_grad, beta_grad);
+
+ auto grad_error = compare_gradients(src_grad, grad_src);
+ dlog << LINFO << "src error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+
+ grad_error = compare_gradients(gamma_grad, grad_gamma);
+ dlog << LINFO << "gamma error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+
+ grad_error = compare_gradients(beta_grad, grad_beta);
+ dlog << LINFO << "beta error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+ }
+
+ void test_batch_normalize_conv()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor src(5,5,4,4), gamma, beta, dest, dest2, dest3, means, vars, gradient_input(5,5,4,4);
+ tt::tensor_rand rnd;
+ rnd.fill_gaussian(src);
+ rnd.fill_gaussian(gradient_input);
+ gamma = matrix_cast<float>(gaussian_randm(1,5, 1));
+ beta = matrix_cast<float>(gaussian_randm(1,5, 2));
+
+ gamma = 1;
+ beta = 0;
+
+ resizable_tensor running_means;
+ resizable_tensor running_variances;
+ batch_normalize_conv(DEFAULT_BATCH_NORM_EPS,dest, means, vars, 1, running_means, running_variances, src, gamma, beta);
+ const double scale = (src.num_samples()*src.nr()*src.nc())/(src.num_samples()*src.nr()*src.nc()-1.0);
+ // Turn back into biased variance estimate because that's how
+ // batch_normalize_conv() works, so if we want to match it this is necessary.
+ running_variances = mat(running_variances)/scale;
+ batch_normalize_conv_inference(DEFAULT_BATCH_NORM_EPS,dest2, src, gamma, beta, running_means, running_variances);
+ DLIB_TEST(max(abs(mat(dest2)-mat(dest))) < 1e-5);
+ cpu::batch_normalize_conv_inference(DEFAULT_BATCH_NORM_EPS,dest3, src, gamma, beta, running_means, running_variances);
+ DLIB_TEST(max(abs(mat(dest3)-mat(dest))) < 1e-5);
+
+
+ auto grad_src = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = src.host()[idx];
+ src.host()[idx] += eps;
+ batch_normalize_conv(DEFAULT_BATCH_NORM_EPS,dest, means, vars, 1, running_means, running_variances, src, gamma, beta);
+ float result = dot(gradient_input, dest);
+ src.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+ auto grad_gamma = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = gamma.host()[idx];
+ gamma.host()[idx] += eps;
+ batch_normalize_conv(DEFAULT_BATCH_NORM_EPS,dest, means, vars, 1, running_means, running_variances, src, gamma, beta);
+ float result = dot(gradient_input, dest);
+ gamma.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+ auto grad_beta = [&](long idx) {
+ auto f = [&](float eps) {
+ const float old = beta.host()[idx];
+ beta.host()[idx] += eps;
+ batch_normalize_conv(DEFAULT_BATCH_NORM_EPS,dest, means, vars, 1, running_means, running_variances, src, gamma, beta);
+ float result = dot(gradient_input, dest);
+ beta.host()[idx] = old;
+ return result;
+ };
+ const float eps = 0.01;
+ return (f(+eps)-f(-eps))/(2*eps);
+ };
+
+
+ resizable_tensor src_grad, gamma_grad, beta_grad;
+ src_grad.copy_size(src);
+ gamma_grad.copy_size(gamma);
+ beta_grad.copy_size(beta);
+ src_grad = 0;
+ gamma_grad = 9;
+ beta_grad = 9;
+
+ batch_normalize_conv_gradient(DEFAULT_BATCH_NORM_EPS,gradient_input, means, vars, src, gamma, src_grad, gamma_grad, beta_grad);
+
+
+ auto grad_error = compare_gradients(src_grad, grad_src);
+ dlog << LINFO << "src error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+
+ grad_error = compare_gradients(gamma_grad, grad_gamma);
+ dlog << LINFO << "gamma error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+
+ grad_error = compare_gradients(beta_grad, grad_beta);
+ dlog << LINFO << "beta error: " << grad_error;
+ DLIB_TEST(grad_error < 0.001);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_basic_tensor_ops()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor dest, src(3,4), A(1,4), B(1,4);
+ src = 2;
+ dest.copy_size(src);
+ affine_transform(dest, src, 2, 3);
+ dlog << LINFO << mat(dest);
+ matrix<float> truth1(3,4), truth2(3,4);
+
+ truth1 = 2;
+ DLIB_TEST(max(abs(truth1-mat(src))) < 1e-5);
+ src *= 2;
+ truth1 = 4;
+ DLIB_TEST(max(abs(truth1-mat(src))) < 1e-5);
+ src = 2;
+
+
+ truth1 = 7;
+ truth2 = 7, 10, 7, 7,
+ 7, 10, 7, 7,
+ 7, 10, 7, 7;
+ DLIB_TEST(max(abs(truth1-mat(dest))) < 1e-5);
+
+ A = 2;
+ B = 3;
+ A.host()[1] = 3;
+ B.host()[1] = 4;
+ dest = 0;
+ affine_transform(dest, src, A, B);
+ dlog << LINFO << mat(dest);
+ DLIB_TEST(max(abs(truth2-mat(dest))) < 1e-5);
+
+ A = matrix_cast<float>(gaussian_randm(3,4, 1));
+ B = matrix_cast<float>(gaussian_randm(3,4, 2));
+ affine_transform(dest, src, A, B);
+ dlog << LINFO << mat(dest);
+ matrix<float> truth3 = pointwise_multiply(mat(src), mat(A)) + mat(B);
+ DLIB_TEST(max(abs(truth3-mat(dest))) < 1e-5);
+
+ matrix<float> truth4 = pointwise_multiply(mat(A), mat(B));
+ tt::multiply(false, A, A, B);
+ DLIB_TEST(max(abs(truth4-mat(A))) < 1e-5);
+ truth4 = pointwise_multiply(mat(A), mat(B)) + mat(A);
+ tt::multiply(true, A, A, B);
+ DLIB_TEST(max(abs(truth4-mat(A))) < 1e-5);
+
+ matrix<float> truth5 = mat(B) > 0.1;
+ dlog << LINFO << truth5;
+ threshold(B, 0.1);
+ DLIB_TEST(max(abs(truth5-mat(B))) < 1e-5);
+
+ int cnt = 0;
+ for(auto& x : A)
+ x = cnt++;
+
+ truth1.set_size(2,2);
+ truth2.set_size(2,2);
+ truth3.set_size(2,2);
+ truth1 = 0,1,2,3;
+ truth2 = 4,5,6,7;
+ truth3 = 8,9,10,11;
+
+ alias_tensor at(2,2);
+ auto A0 = at(A,0);
+ auto A4 = at(A,4);
+ auto A8 = at(const_cast<const resizable_tensor&>(A),8);
+ DLIB_TEST(mat(A0) == truth1);
+ DLIB_TEST(mat(at(A,4)) == truth2);
+ DLIB_TEST(mat(A8) == truth3);
+
+ A4 += uniform_matrix<float>(2,2,2);
+ truth2 += 2;
+ DLIB_TEST(mat(A4) == truth2);
+ truth1 = trans(reshape_to_column_vector(truth1));
+ truth2 = trans(reshape_to_column_vector(truth2));
+ truth3 = trans(reshape_to_column_vector(truth3));
+
+ DLIB_TEST(mat(A) == join_cols(truth1,join_cols(truth2,truth3)));
+
+ affine_transform(A,A,1,2);
+ truth1 += 2;
+ truth2 += 2;
+ truth3 += 2;
+ DLIB_TEST(mat(at(A,4)) == reshape(truth2,2,2));
+ DLIB_TEST(mat(A) == join_cols(truth1,join_cols(truth2,truth3)));
+
+ {
+ resizable_tensor dest(3,4);
+ resizable_tensor A, B;
+ A = dest;
+ B = dest;
+
+ tensor_rand rnd;
+ rnd.fill_uniform(dest);
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+
+ dest.set_size(1,4);
+
+ tt::multiply(false, dest, A, B);
+ DLIB_TEST(max(abs(mat(dest)-sum_rows(pointwise_multiply(mat(A),mat(B))))) < 1e-6);
+
+ A.set_size(1,4);
+ rnd.fill_uniform(A);
+ matrix<float> AA = join_cols(mat(A),mat(A)); AA = join_cols(mat(A),AA);
+
+ tt::multiply(false, dest, A, B);
+ DLIB_TEST(max(abs(mat(dest)-sum_rows(pointwise_multiply(AA,mat(B))))) < 1e-6);
+
+ tt::multiply(false, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-sum_rows(pointwise_multiply(AA,mat(B))))) < 1e-6);
+ matrix<float> prevdest = mat(dest);
+ tt::multiply(true, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-prevdest-sum_rows(pointwise_multiply(AA,mat(B))))) < 1e-6);
+
+ dest.set_size(3,4);
+ tt::multiply(false, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-pointwise_multiply(AA,mat(B)))) < 1e-6);
+ prevdest = mat(dest);
+ tt::multiply(true, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-prevdest-pointwise_multiply(AA,mat(B)))) < 1e-6);
+
+ tt::multiply(false, dest, A, B);
+ DLIB_TEST(max(abs(mat(dest)-pointwise_multiply(AA,mat(B)))) < 1e-6);
+ prevdest = mat(dest);
+ tt::multiply(true, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-prevdest-pointwise_multiply(AA,mat(B)))) < 1e-6);
+ }
+
+ {
+ resizable_tensor A, B, truth;
+ A.set_size(2,3,4,5);
+ truth.copy_size(A);
+ B.copy_size(A);
+
+ A = 4;
+ B = 1;
+ truth = 1;
+ DLIB_TEST(max(abs(mat(B)- mat(truth))) < 1e-5);
+ memcpy(A, truth);
+ DLIB_TEST(max(abs(mat(A)- mat(truth))) < 1e-5);
+
+ A = 4;
+ A.host();
+ B.host();
+ memcpy(A, truth);
+ DLIB_TEST(max(abs(mat(A)- mat(truth))) < 1e-5);
+
+#ifdef DLIB_USE_CUDA
+ A = 4;
+ A.device();
+ B.host();
+ memcpy(A, truth);
+ DLIB_TEST(max(abs(mat(A)- mat(truth))) < 1e-5);
+
+ A = 4;
+ A.device();
+ B.device();
+ memcpy(A, truth);
+ DLIB_TEST(max(abs(mat(A)- mat(truth))) < 1e-5);
+
+ A = 4;
+ A.host();
+ B.device();
+ memcpy(A, truth);
+ DLIB_TEST(max(abs(mat(A)- mat(truth))) < 1e-5);
+
+ A = 4;
+ A.host_write_only();
+ B.device();
+ memcpy(A, truth);
+ DLIB_TEST(max(abs(mat(A)- mat(truth))) < 1e-5);
+#endif
+ }
+
+ {
+ resizable_tensor A, B;
+ A.set_size(11);
+ B.copy_size(A);
+
+ A = 4;
+ B = 1;
+ matrix<float> truth;
+
+
+ alias_tensor at(5);
+ A = 4;
+ A.host();
+ B.host();
+ {
+ // non-aliasing test
+ auto aA = at(A,5);
+ auto aB = at(B,5);
+ memcpy(aA, aB);
+ truth = {4,4,4,4,4, 1,1,1,1,1, 4};
+ DLIB_TEST(max(abs(mat(A)- truth)) < 1e-5);
+ }
+ {
+ // aliasing test
+ auto aA = at(A,1);
+ auto aB = at(A,6);
+ memcpy(aA, aB);
+ truth = {4,1,1,1,1, 4,1,1,1,1, 4};
+ DLIB_TEST(max(abs(mat(A)- truth)) < 1e-5);
+ }
+
+
+#ifdef DLIB_USE_CUDA
+ A = 4;
+ A.device();
+ B.host();
+ {
+ // non-aliasing test
+ auto aA = at(A,5);
+ auto aB = at(B,5);
+ memcpy(aA, aB);
+ truth = {4,4,4,4,4, 1,1,1,1,1, 4};
+ DLIB_TEST(max(abs(mat(A)- truth)) < 1e-5);
+ }
+ {
+ // aliasing test
+ auto aA = at(A,1);
+ auto aB = at(A,6);
+ memcpy(aA, aB);
+ truth = {4,1,1,1,1, 4,1,1,1,1, 4};
+ DLIB_TEST(max(abs(mat(A)- truth)) < 1e-5);
+ }
+
+
+ A = 4;
+ A.device();
+ B.device();
+ {
+ // non-aliasing test
+ auto aA = at(A,5);
+ auto aB = at(B,5);
+ memcpy(aA, aB);
+ truth = {4,4,4,4,4, 1,1,1,1,1, 4};
+ DLIB_TEST(max(abs(mat(A)- truth)) < 1e-5);
+ }
+ {
+ // aliasing test
+ auto aA = at(A,1);
+ auto aB = at(A,6);
+ memcpy(aA, aB);
+ truth = {4,1,1,1,1, 4,1,1,1,1, 4};
+ DLIB_TEST(max(abs(mat(A)- truth)) < 1e-5);
+ }
+
+ A = 4;
+ A.host();
+ B.device();
+ {
+ // non-aliasing test
+ auto aA = at(A,5);
+ auto aB = at(B,5);
+ memcpy(aA, aB);
+ truth = {4,4,4,4,4, 1,1,1,1,1, 4};
+ DLIB_TEST(max(abs(mat(A)- truth)) < 1e-5);
+ }
+ {
+ // aliasing test
+ auto aA = at(A,1);
+ auto aB = at(A,6);
+ memcpy(aA, aB);
+ truth = {4,1,1,1,1, 4,1,1,1,1, 4};
+ DLIB_TEST(max(abs(mat(A)- truth)) < 1e-5);
+ }
+
+#endif
+ }
+
+ {
+ resizable_tensor A(4,5), B(4);
+
+ tensor_rand rnd;
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+
+ float alpha = 1.4;
+ float beta = 0.5;
+
+ matrix<float> a(mat(A)), b(mat(B));
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ set_colm(a,c) = beta*colm(a,c) + alpha*b;
+ }
+
+ tt::add(beta, A, alpha, B);
+ DLIB_TEST_MSG(max(abs(mat(A)-a)) < 1e-6, max(abs(mat(A)-a)));
+
+ beta = 0;
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ set_colm(a,c) = beta*colm(a,c) + alpha*b;
+ }
+
+ tt::add(beta, A, alpha, B);
+ DLIB_TEST(max(abs(mat(A)-a)) < 1e-6);
+ }
+
+ {
+ resizable_tensor A, B;
+ A.set_size(2,3,4,5);
+ B.set_size(2,3,4,5);
+
+ tensor_rand rnd;
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+
+ matrix<float> truth;
+
+ truth = 2*mat(A) + 3*mat(B);
+ tt::add(2, A, 3, B);
+ DLIB_TEST(max(abs(mat(A)-truth )) < 1e-6);
+
+
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+ truth = 0*mat(A) + 3*mat(B);
+ tt::add(0, A, 3, B);
+ DLIB_TEST(max(abs(mat(A)-truth )) < 1e-6);
+
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+ truth = 1*mat(A) + 0*mat(B);
+ tt::add(1, A, 0, B);
+ DLIB_TEST(max(abs(mat(A)-truth )) < 1e-6);
+
+
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+ truth = 0*mat(A) + 0*mat(B);
+ tt::add(0, A, 0, B);
+ DLIB_TEST(max(abs(mat(A)-truth )) < 1e-6);
+
+
+ B.set_size(1,3,4,5);
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+ truth = 2*mat(A) + 3*join_cols(mat(B), mat(B));
+ tt::add(2, A, 3, B);
+ DLIB_TEST(max(abs(mat(A)-truth )) < 1e-6);
+ DLIB_TEST(A.num_samples()==2);
+
+ B.set_size(1,1,4,5);
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+ matrix<float> temp = join_rows(mat(B), join_rows(mat(B),mat(B)));
+ truth = 2*mat(A) + 3*join_cols(temp,temp);
+ tt::add(2, A, 3, B);
+ DLIB_TEST_MSG(max(abs(mat(A)-truth )) < 1e-6, max(abs(mat(A)-truth )));
+
+ B.set_size(1,3,1,1);
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+ resizable_tensor AA(A), BB(B);
+ tt::add(2, A, 3, B);
+ cpu::add(2, AA, 3, BB);
+ DLIB_TEST_MSG(max(abs(mat(A)-mat(AA) )) < 1e-6, max(abs(mat(A)-mat(AA) )));
+ }
+
+ {
+ print_spinner();
+ resizable_tensor dest1(123,456), dest2(123,456);
+ resizable_tensor src1(123,456), src2(123,456);
+
+ tt::tensor_rand rnd;
+
+ rnd.fill_uniform(src1); tt::affine_transform(src1, src1, 1, 2); src2 = src1; // random in range [2, 3]
+ dest1 = exp(mat(src1));
+ tt::exp(dest2, src2);
+ tt::exp(src2, src2); // should work in place
+ DLIB_TEST_MSG(max(abs(mat(dest1)-mat(dest2))) < 1e-5, max(abs(mat(dest1)-mat(dest2))));
+ DLIB_TEST(max(abs(mat(dest1)-mat(src2))) < 1e-5);
+
+ rnd.fill_uniform(src1); tt::affine_transform(src1, src1, 1, 2); src2 = src1; // random in range [2, 3]
+ dest1 = log(mat(src1));
+ tt::log(dest2, src2);
+ tt::log(src2, src2); // should work in place
+ DLIB_TEST(max(abs(mat(dest1)-mat(dest2))) < 1e-5);
+ DLIB_TEST(max(abs(mat(dest1)-mat(src2))) < 1e-5);
+
+ rnd.fill_uniform(src1); tt::affine_transform(src1, src1, 1, 2); src2 = src1; // random in range [2, 3]
+ dest1 = log10(mat(src1));
+ tt::log10(dest2, src2);
+ tt::log10(src2, src2); // should work in place
+ DLIB_TEST(max(abs(mat(dest1)-mat(dest2))) < 1e-5);
+ DLIB_TEST(max(abs(mat(dest1)-mat(src2))) < 1e-5);
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+#ifdef DLIB_USE_CUDA
+
+ void test_scale_channels()
+ {
+ tt::tensor_rand rnd;
+
+ resizable_tensor dest1(2,3,4,5), dest2;
+ rnd.fill_gaussian(dest1);
+ dest2 = dest1;
+
+ resizable_tensor src(2,3,4,5);
+ resizable_tensor scales(2,3);
+ rnd.fill_gaussian(src);
+ rnd.fill_gaussian(scales);
+
+
+ cpu::scale_channels(true, dest1, src, scales);
+ cuda::scale_channels(true, dest2, src, scales);
+
+ DLIB_TEST(max(abs(mat(dest1)-mat(dest2))) < 1e-6);
+
+ cpu::scale_channels(false, dest1, src, scales);
+ cuda::scale_channels(false, dest2, src, scales);
+
+ DLIB_TEST(max(abs(mat(dest1)-mat(dest2))) < 1e-6);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_affine_rect()
+ {
+ dlib::rand rnd;
+
+ for (int iter = 0; iter < 20; ++iter)
+ {
+
+ long nr = 1 + rnd.get_random_32bit_number()%10;
+ long nc = 1 + rnd.get_random_32bit_number()%10;
+
+ resizable_tensor dest1(nr,nc), dest2(nr,nc), src1(nr,nc), src2(nr,nc), src3(nr,nc);
+ matrix<float> dest3;
+
+ dest1 = 1;
+ dest2 = 1;
+ dest3 = mat(dest1);
+ src1 = 2;
+ src2 = 3;
+ src3 = 4;
+
+ point p1(rnd.get_random_32bit_number()%nc, rnd.get_random_32bit_number()%nr);
+ point p2(rnd.get_random_32bit_number()%nc, rnd.get_random_32bit_number()%nr);
+ rectangle rect(p1,p2);
+
+ cuda::affine_transform(rect, dest1, src1, src2, src3, 2,3,4);
+
+ cpu::affine_transform(rect, dest2, src1, src2, src3, 2,3,4);
+
+ DLIB_TEST(mat(dest1) == mat(dest2));
+
+ set_subm(dest3,rect) = 2*subm(mat(src1),rect) + 3*subm(mat(src2),rect) + 4*subm(mat(src3),rect);
+ DLIB_TEST(dest3 == mat(dest1));
+
+ dest1 = 1;
+ tt::affine_transform(rect, dest1, src1, src2, src3, 2,3,4);
+ DLIB_TEST(dest3 == mat(dest1));
+ }
+ }
+
+ void test_conv()
+ {
+ cuda::tensor_conv conv1;
+ cpu::tensor_conv conv2;
+
+ dlib::rand prnd;
+ for (int iter = 0; iter < 400; ++iter)
+ {
+ print_spinner();
+
+ resizable_tensor data(prnd.get_random_32bit_number()%5+1,
+ prnd.get_random_32bit_number()%5+1,
+ prnd.get_random_32bit_number()%25+1,
+ prnd.get_random_32bit_number()%25+1
+ );
+ resizable_tensor filters(
+ prnd.get_random_32bit_number()%5+1,
+ data.k(),
+ prnd.get_random_32bit_number()%6+1,
+ prnd.get_random_32bit_number()%6+1
+ );
+
+ tt::tensor_rand rnd;
+ rnd.fill_uniform(data);
+ rnd.fill_uniform(filters);
+
+
+ resizable_tensor output1, output2;
+
+
+ const int stride_y = prnd.get_random_32bit_number()%5+1;
+ const int stride_x = prnd.get_random_32bit_number()%5+1;
+ int padding_y = prnd.get_random_32bit_number()%(filters.nr()/2+1);
+ int padding_x = prnd.get_random_32bit_number()%(filters.nc()/2+1);
+ if (!(filters.nr() <= data.nr() + 2*padding_y))
+ padding_y = (filters.nr()-data.nr()+1)/2;
+ if (!(filters.nc() <= data.nc() + 2*padding_x))
+ padding_x = (filters.nc()-data.nc()+1)/2;
+ conv1.setup(data,filters,stride_y,stride_x,padding_y,padding_x);
+ conv1(false, output1, data, filters);
+ conv2.setup(data,filters,stride_y,stride_x,padding_y,padding_x);
+ conv2(false, output2, data, filters);
+ dlog << LINFO << "forward error: "<< max(abs(mat(output1)-mat(output2)));
+ DLIB_TEST_MSG(max(abs(mat(output1)-mat(output2))) < 1e-3, max(abs(mat(output1)-mat(output2)))
+ <<"\n\t padding_y: "<< padding_y
+ <<"\n\t padding_x: "<< padding_x
+ );
+
+ conv1(true, output1, data, filters);
+ conv2(true, output2, data, filters);
+ dlog << LINFO << "forward error: "<< max(abs(mat(output1)-mat(output2)));
+ DLIB_TEST_MSG(max(abs(mat(output1)-mat(output2))) < 1e-3, max(abs(mat(output1)-mat(output2)))
+ <<"\n\t padding_y: "<< padding_y
+ <<"\n\t padding_x: "<< padding_x
+ );
+
+
+
+ resizable_tensor gi, data_gradient1, data_gradient2;
+ gi.copy_size(output1);
+ rnd.fill_uniform(gi);
+
+ data_gradient1.copy_size(data);
+ data_gradient2.copy_size(data);
+ data_gradient1 = 1;
+ data_gradient2 = 1;
+
+ conv1.get_gradient_for_data(true, gi, filters, data_gradient1);
+ conv2.get_gradient_for_data(true, gi, filters, data_gradient2);
+
+ dlog << LINFO << "data gradient error: "<< max(abs(mat(data_gradient1)-mat(data_gradient2)));
+ DLIB_TEST(max(abs(mat(data_gradient1)-mat(data_gradient2))) < 1e-3);
+
+ conv1.get_gradient_for_data(false, gi, filters, data_gradient1);
+ conv2.get_gradient_for_data(false, gi, filters, data_gradient2);
+
+ dlog << LINFO << "data gradient error: "<< max(abs(mat(data_gradient1)-mat(data_gradient2)));
+ DLIB_TEST(max(abs(mat(data_gradient1)-mat(data_gradient2))) < 1e-3);
+
+
+ resizable_tensor filter_gradient1, filter_gradient2;
+ gi.copy_size(output1);
+ rnd.fill_uniform(gi);
+
+ filter_gradient1.copy_size(filters);
+ filter_gradient2.copy_size(filters);
+ filter_gradient1 = 1;
+ filter_gradient2 = 1;
+
+ conv1.get_gradient_for_filters(false, gi, data, filter_gradient1);
+ conv2.get_gradient_for_filters(false, gi, data, filter_gradient2);
+
+ dlog << LINFO << "filter gradient error: "<< max(abs(mat(filter_gradient1)-mat(filter_gradient2)));
+ DLIB_TEST_MSG(max(abs(mat(filter_gradient1)-mat(filter_gradient2))) < 1e-3, max(abs(mat(filter_gradient1)-mat(filter_gradient2))));
+
+
+ conv1.get_gradient_for_filters(true, gi, data, filter_gradient1);
+ conv2.get_gradient_for_filters(true, gi, data, filter_gradient2);
+
+ dlog << LINFO << "filter gradient error: "<< max(abs(mat(filter_gradient1)-mat(filter_gradient2)));
+ DLIB_TEST_MSG(max(abs(mat(filter_gradient1)-mat(filter_gradient2))) < 2e-3, max(abs(mat(filter_gradient1)-mat(filter_gradient2))));
+ }
+ }
+
+ void compare_adam()
+ {
+ float t = 2;
+ tt::tensor_rand rnd;
+ resizable_tensor s, m, v, params, params_grad;
+ s.set_size(89,90,60,73);
+ m.copy_size(s);
+ v.copy_size(s);
+ params.copy_size(s);
+ params_grad.copy_size(s);
+
+ rnd.fill_uniform(s);
+ rnd.fill_uniform(m);
+ rnd.fill_uniform(v);
+ rnd.fill_uniform(params);
+ rnd.fill_uniform(params_grad);
+
+ resizable_tensor mm(m), vv(v);
+ cpu::compute_adam_update(0,params.size(),s, mm, vv, t, 0.01, 0.001, 0.9, 0.99, params, params_grad);
+ matrix<float> s1 = mat(s);
+
+ rnd.fill_uniform(s);
+ cuda::compute_adam_update(0,params.size(),s, m, v, t, 0.01, 0.001, 0.9, 0.99, params, params_grad);
+ matrix<float> s2 = mat(s);
+
+ DLIB_TEST_MSG(max(abs(s1-s2)) < 1e-6, max(abs(s1-s2)));
+ DLIB_TEST_MSG(max(abs(mat(m)-mat(mm))) < 1e-6, max(abs(mat(m)-mat(mm))));
+ DLIB_TEST_MSG(max(abs(mat(v)-mat(vv))) < 1e-6, max(abs(mat(v)-mat(vv))));
+ }
+
+ void test_multiply_zero_padded()
+ {
+ print_spinner();
+ dlib::rand rnd;
+ tt::tensor_rand trnd;
+ for (int iter = 0; iter < 300; ++iter)
+ {
+ resizable_tensor dest1(rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1);
+ resizable_tensor dest2;
+ dest2.copy_size(dest1);
+ resizable_tensor src1(rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1);
+ resizable_tensor src2(rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1);
+
+ trnd.fill_uniform(dest1);
+ trnd.fill_uniform(dest2);
+ trnd.fill_uniform(src1);
+ trnd.fill_uniform(src2);
+ cpu::multiply_zero_padded(false, dest1, src1, src2);
+ cuda::multiply_zero_padded(false, dest2, src1, src2);
+ DLIB_TEST(max(abs(mat(dest1) - mat(dest2))) < 1e-5);
+
+ cpu::multiply_zero_padded(true, dest1, src1, src2);
+ cuda::multiply_zero_padded(true, dest2, src1, src2);
+ DLIB_TEST(max(abs(mat(dest1) - mat(dest2))) < 1e-5);
+ }
+
+ // make sure we have a test for the case where all tensors have the same
+ // dimensions.
+ resizable_tensor dest1(3,4,5,6);
+ resizable_tensor dest2;
+ resizable_tensor src1;
+ resizable_tensor src2;
+ dest2.copy_size(dest1);
+ src1.copy_size(dest1);
+ src2.copy_size(dest1);
+
+ trnd.fill_uniform(dest1);
+ trnd.fill_uniform(dest2);
+ trnd.fill_uniform(src1);
+ trnd.fill_uniform(src2);
+ cpu::multiply_zero_padded(false, dest1, src1, src2);
+ cuda::multiply_zero_padded(false, dest2, src1, src2);
+ DLIB_TEST(max(abs(mat(dest1) - mat(dest2))) < 1e-5);
+
+ cpu::multiply_zero_padded(true, dest1, src1, src2);
+ cuda::multiply_zero_padded(true, dest2, src1, src2);
+ DLIB_TEST(max(abs(mat(dest1) - mat(dest2))) < 1e-5);
+ }
+
+ void test_add()
+ {
+ print_spinner();
+ dlib::rand rnd;
+ tt::tensor_rand trnd;
+ for (int iter = 0; iter < 300; ++iter)
+ {
+ resizable_tensor dest1(rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1);
+ resizable_tensor dest2;
+ dest2.copy_size(dest1);
+ resizable_tensor src1(rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1);
+ resizable_tensor src2(rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1,
+ rnd.get_random_32bit_number()%4+1);
+
+ trnd.fill_uniform(dest1);
+ trnd.fill_uniform(dest2);
+ trnd.fill_uniform(src1);
+ trnd.fill_uniform(src2);
+ cpu::add(dest1, src1, src2);
+ cuda::add(dest2, src1, src2);
+
+ DLIB_TEST(max(abs(mat(dest1) - mat(dest2))) < 1e-5);
+ }
+
+ // make sure we have a test for the case where all tensors have the same
+ // dimensions.
+ resizable_tensor dest1(3,4,5,6);
+ resizable_tensor dest2;
+ resizable_tensor src1;
+ resizable_tensor src2;
+ dest2.copy_size(dest1);
+ src1.copy_size(dest1);
+ src2.copy_size(dest1);
+
+ trnd.fill_uniform(dest1);
+ trnd.fill_uniform(dest2);
+ trnd.fill_uniform(src1);
+ trnd.fill_uniform(src2);
+
+ cpu::add(dest1, src1, src2);
+ cuda::add(dest2, src1, src2);
+
+ DLIB_TEST(max(abs(mat(dest1) - mat(dest2))) < 1e-5);
+ }
+
+ void test_more_ops(const long nr, const long nc)
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ // We are going to make sure that the CPU implementation of these things matches
+ // the CUDA implementation.
+
+ tensor_rand rnd;
+
+ resizable_tensor dest(nr,nc), src(nr,nc), dest2, src2;
+ resizable_tensor srcb(nr,nc), srcc(nr,nc), srcb2, srcc2;
+
+
+ rnd.fill_uniform(dest);
+ rnd.fill_uniform(src);
+ dest2 = dest; src2 = src;
+ cuda::multiply(false, dest, dest, src);
+ cpu::multiply(false, dest2, dest2, src2);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+ cuda::multiply(true, dest, dest, src);
+ cpu::multiply(true, dest2, dest2, src2);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+
+
+ rnd.fill_uniform(dest);
+ rnd.fill_uniform(src);
+ dest2 = dest; src2 = src;
+ cuda::affine_transform(dest, src, 2, 3);
+ cpu::affine_transform(dest2, src2, 2, 3);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+
+ rnd.fill_uniform(dest);
+ rnd.fill_uniform(src);
+ rnd.fill_uniform(srcb);
+ dest2 = dest; src2 = src; srcb2 = srcb;
+ cuda::affine_transform(dest, src, srcb, 2, 3, 4);
+ cpu::affine_transform(dest2, src2, srcb2, 2, 3, 4);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+
+ rnd.fill_uniform(dest);
+ rnd.fill_uniform(src);
+ rnd.fill_uniform(srcb);
+ rnd.fill_uniform(srcc);
+ dest2 = dest; src2 = src; srcb2 = srcb; srcc2 = srcc;
+ cuda::affine_transform(dest, src, srcb, srcc, 2, 3, 4, 5);
+ cpu::affine_transform(dest2, src2, srcb2, srcc2, 2, 3, 4, 5);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+
+ cuda::affine_transform(dest, src, srcb, srcc, 2, 3, 4, 0);
+ cpu::affine_transform(dest2, src2, srcb2, srcc2, 2, 3, 4, 0);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+
+ cuda::affine_transform_range(0, dest.size(), dest, src, srcb, srcc, 2, 3, 4);
+ cpu::affine_transform_range(0, dest2.size(), dest2, src2, srcb2, srcc2, 2, 3, 4);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+
+ if (3 < dest.size())
+ {
+ dest = 999;
+ dest2 = 999;
+ cuda::affine_transform_range(3, dest.size()-1, dest, src, srcb, srcc, 2, 3, 4);
+ cpu::affine_transform_range(3, dest2.size()-1, dest2, src2, srcb2, srcc2, 2, 3, 4);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+
+ cuda::affine_transform_range(dest.size(), dest.size(), dest, src, srcb, srcc, 2, 3, 4);
+ cpu::affine_transform_range(dest2.size(), dest2.size(), dest2, src2, srcb2, srcc2, 2, 3, 4);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+ }
+
+
+ rnd.fill_uniform(dest);
+ rnd.fill_uniform(src);
+ rnd.fill_uniform(srcb);
+ rnd.fill_uniform(srcc);
+ dest2 = dest; src2 = src; srcb2 = srcb; srcc2 = srcc;
+ cuda::affine_transform(dest, src, srcb, srcc);
+ cpu::affine_transform(dest2, src2, srcb2, srcc2);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+ // now exercise code path where the A/B tensors have num_samples()==1
+ srcb.set_size(1,nc);
+ srcc.set_size(1,nc);
+ rnd.fill_uniform(dest);
+ rnd.fill_uniform(src);
+ rnd.fill_uniform(srcb);
+ rnd.fill_uniform(srcc);
+ dest2 = dest; src2 = src; srcb2 = srcb; srcc2 = srcc;
+ cuda::affine_transform(dest, src, srcb, srcc);
+ cpu::affine_transform(dest2, src2, srcb2, srcc2);
+ DLIB_TEST(equal(mat(dest),mat(dest2)));
+
+
+ rnd.fill_uniform(src);
+ src2 = src;
+ cuda::threshold(src, 0.5);
+ cpu::threshold(src2, 0.5);
+ DLIB_TEST(equal(mat(src),mat(src2)));
+
+ {
+ resizable_tensor dest(3,4);
+ resizable_tensor A, B;
+ A = dest;
+ B = dest;
+
+ rnd.fill_uniform(dest);
+ rnd.fill_uniform(A);
+ rnd.fill_uniform(B);
+
+ dest.set_size(1,4);
+
+ cuda::multiply(false, dest, A, B);
+ DLIB_TEST_MSG(max(abs(mat(dest)-sum_rows(pointwise_multiply(mat(A),mat(B))))) < 1e-6, max(abs(mat(dest)-sum_rows(pointwise_multiply(mat(A),mat(B))))));
+
+ A.set_size(1,4);
+ rnd.fill_uniform(A);
+ matrix<float> AA = join_cols(mat(A),mat(A)); AA = join_cols(mat(A),AA);
+
+ cuda::multiply(false, dest, A, B);
+ DLIB_TEST(max(abs(mat(dest)-sum_rows(pointwise_multiply(AA,mat(B))))) < 1e-6);
+
+ cuda::multiply(false, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-sum_rows(pointwise_multiply(AA,mat(B))))) < 1e-6);
+ matrix<float> prevdest = mat(dest);
+ cuda::multiply(true, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-prevdest-sum_rows(pointwise_multiply(AA,mat(B))))) < 1e-6);
+
+ dest.set_size(3,4);
+ cuda::multiply(false, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-pointwise_multiply(AA,mat(B)))) < 1e-6);
+ prevdest = mat(dest);
+ cuda::multiply(true, dest, B, A);
+ DLIB_TEST(max(abs(mat(dest)-prevdest-pointwise_multiply(AA,mat(B)))) < 1e-6);
+
+ cuda::multiply(false, dest, A, B);
+ DLIB_TEST(max(abs(mat(dest)-pointwise_multiply(AA,mat(B)))) < 1e-6);
+ }
+
+ {
+ resizable_tensor invnorms1, invnorms2;
+ resizable_tensor data(4,5), out1, out2;
+ rnd.fill_uniform(data);
+
+ const double eps = 0.1;
+
+ invnorms2 = reciprocal(sqrt(sum_cols(squared(mat(data))) + eps));
+ tt::inverse_norms(invnorms1, data, eps);
+ DLIB_TEST(max(abs(mat(invnorms1)-mat(invnorms2))) < 1e-6);
+
+ out1.copy_size(data);
+ tt::scale_rows(out1, data, invnorms1);
+ out2 = scale_rows(mat(data), mat(invnorms1));
+ DLIB_TEST(max(abs(mat(out1)-mat(out2))) < 1e-6);
+ }
+
+ {
+ resizable_tensor a(123,432), b(123,432);
+ rnd.fill_gaussian(a);
+ rnd.fill_gaussian(b);
+
+ resizable_tensor out;
+ dot_prods(out, a,b);
+ const matrix<float> truth = sum_cols(pointwise_multiply(mat(a), mat(b)));
+ DLIB_TEST(max(abs(mat(out) - truth)) < 1e-4);
+ out = 0;
+ DLIB_TEST(max(abs(mat(out) - truth)) > 1e-2);
+ dot_prods(false, out, a,b);
+ DLIB_TEST(max(abs(mat(out) - truth)) < 1e-4);
+ dot_prods(true, out, a,b);
+ DLIB_TEST(max(abs(mat(out)/2 - truth)) < 1e-4);
+ DLIB_TEST(max(abs(mat(out) - truth)) > 1e-2);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void compare_bn_gpu_and_cpu()
+ {
+ print_spinner();
+ resizable_tensor dest, dest2;
+ resizable_tensor means, means2;
+ resizable_tensor invstds, invstds2;
+ resizable_tensor running_means, running_means2;
+ resizable_tensor running_variances, running_variances2;
+ resizable_tensor src(64,20,100,100);
+ resizable_tensor gamma(1,20,100,100);
+ resizable_tensor beta(1,20,100,100);
+ gamma = 2;
+ beta = 3;
+ tt::tensor_rand rnd;
+ rnd.fill_uniform(src);
+
+
+ cpu::batch_normalize(DEFAULT_BATCH_NORM_EPS,dest, means, invstds, 1, running_means, running_variances, src, gamma, beta);
+ cuda::batch_normalize(DEFAULT_BATCH_NORM_EPS,dest2,means2,invstds2, 1, running_means2, running_variances2, src, gamma, beta);
+
+ dlog << LINFO << "dest error: "<< max(abs(mat(dest) -mat(dest2)));
+ dlog << LINFO << "means error: "<< max(abs(mat(means) -mat(means2)));
+ dlog << LINFO << "invstds error: "<< max(abs(mat(invstds) -mat(invstds2)));
+ dlog << LINFO << "running_means error: "<< max(abs(mat(running_means) -mat(running_means2)));
+ dlog << LINFO << "running_variances error: "<< max(abs(mat(running_variances) -mat(running_variances2)));
+
+ DLIB_TEST(max(abs(mat(dest) -mat(dest2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(means) -mat(means2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(invstds) -mat(invstds2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(running_means) -mat(running_means2))) < 1e-4);
+ DLIB_TEST_MSG(max(abs(mat(running_variances) -mat(running_variances2))) < 1e-4,
+ mean(mat(running_variances))
+ << "\n" << mean(mat(running_variances2))
+ << "\n" << max(abs(mat(running_variances) -mat(running_variances2)))
+ << "\n" << mean(abs(mat(running_variances) -mat(running_variances2)))
+ );
+
+
+ // now check that the gradients match as well
+ resizable_tensor gradient_input;
+ resizable_tensor src_grad, gamma_grad, beta_grad;
+ resizable_tensor src_grad2, gamma_grad2, beta_grad2;
+ gradient_input.copy_size(dest);
+ src_grad.copy_size(src); src_grad = 0; src_grad2 = src_grad;
+ gamma_grad.copy_size(gamma); gamma_grad = 0; gamma_grad2 = gamma_grad;
+ beta_grad.copy_size(beta); beta_grad = 0; beta_grad2 = beta_grad;
+ rnd.fill_uniform(gradient_input);
+
+
+ cpu::batch_normalize_gradient(DEFAULT_BATCH_NORM_EPS,gradient_input, means, invstds, src, gamma, src_grad, gamma_grad, beta_grad);
+ cuda::batch_normalize_gradient(DEFAULT_BATCH_NORM_EPS,gradient_input, means, invstds, src, gamma, src_grad2, gamma_grad2, beta_grad2);
+
+ dlog << LINFO << "src_grad error: " << max(abs(mat(src_grad)-mat(src_grad2)));
+ dlog << LINFO << "gamma_grad error: " << max(abs(mat(gamma_grad)-mat(gamma_grad2)));
+ dlog << LINFO << "beta_grad error: " << max(abs(mat(beta_grad)-mat(beta_grad2)));
+ DLIB_TEST(max(abs(mat(src_grad)-mat(src_grad2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(gamma_grad)-mat(gamma_grad2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(beta_grad)-mat(beta_grad2))) < 1e-4);
+ }
+
+ void compare_bn_conv_gpu_and_cpu()
+ {
+ print_spinner();
+ resizable_tensor dest, dest2;
+ resizable_tensor means, means2;
+ resizable_tensor invstds, invstds2;
+ resizable_tensor running_means, running_means2;
+ resizable_tensor running_variances, running_variances2;
+ resizable_tensor src(2,8,10,9);
+ resizable_tensor gamma(1,8);
+ resizable_tensor beta(1,8);
+ gamma = 2;
+ beta = 3;
+ tt::tensor_rand rnd;
+ rnd.fill_uniform(src);
+
+ cpu::batch_normalize_conv(DEFAULT_BATCH_NORM_EPS,dest,means,invstds,1,running_means,running_variances, src, gamma, beta);
+ cuda::batch_normalize_conv(DEFAULT_BATCH_NORM_EPS,dest2,means2,invstds2,1,running_means2,running_variances2, src, gamma, beta);
+
+ dlog << LINFO << "dest error: "<< max(abs(mat(dest) -mat(dest2)));
+ dlog << LINFO << "means error: "<< max(abs(mat(means) -mat(means2)));
+ dlog << LINFO << "invstds error: "<< max(abs(mat(invstds) -mat(invstds2)));
+ dlog << LINFO << "running_means error: "<< max(abs(mat(running_means) -mat(running_means2)));
+ dlog << LINFO << "running_variances error: "<< max(abs(mat(running_variances) -mat(running_variances2)));
+
+ DLIB_TEST(max(abs(mat(dest) -mat(dest2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(means) -mat(means2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(invstds) -mat(invstds2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(running_means) -mat(running_means2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(running_variances) -mat(running_variances2))) < 1e-4);
+
+ resizable_tensor gradient_input;
+ resizable_tensor src_grad, gamma_grad, beta_grad;
+ resizable_tensor src_grad2, gamma_grad2, beta_grad2;
+ gradient_input.copy_size(dest);
+ src_grad.copy_size(src); src_grad = 0; src_grad2 = src_grad;
+ gamma_grad.copy_size(gamma); gamma_grad = 0; gamma_grad2 = gamma_grad;
+ beta_grad.copy_size(beta); beta_grad = 0; beta_grad2 = beta_grad;
+ rnd.fill_uniform(gradient_input);
+
+
+ cpu::batch_normalize_conv_gradient(DEFAULT_BATCH_NORM_EPS,gradient_input, means, invstds, src, gamma, src_grad, gamma_grad, beta_grad);
+ cuda::batch_normalize_conv_gradient(DEFAULT_BATCH_NORM_EPS,gradient_input, means, invstds, src, gamma, src_grad2, gamma_grad2, beta_grad2);
+
+ dlog << LINFO << "src_grad error: " << max(abs(mat(src_grad)-mat(src_grad2)));
+ dlog << LINFO << "gamma_grad error: " << max(abs(mat(gamma_grad)-mat(gamma_grad2)));
+ dlog << LINFO << "beta_grad error: " << max(abs(mat(beta_grad)-mat(beta_grad2)));
+ DLIB_TEST(max(abs(mat(src_grad)-mat(src_grad2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(gamma_grad)-mat(gamma_grad2))) < 1e-4);
+ DLIB_TEST(max(abs(mat(beta_grad)-mat(beta_grad2))) < 1e-4);
+ }
+
+
+ void test_more_ops2()
+ {
+ dlib::rand rnd;
+ tt::tensor_rand trand;
+
+ for (int iter = 0; iter < 100; ++iter)
+ {
+ print_spinner();
+ resizable_tensor dest1, dest2, src1, src2;
+ src1.set_size(rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1);
+ dest1.copy_size(src1);
+ dest2.copy_size(src1);
+ src2.set_size(1,src1.k(),1,1);
+
+ trand.fill_uniform(dest1);
+ trand.fill_uniform(dest2);
+ trand.fill_uniform(src1);
+ trand.fill_uniform(src2);
+
+ cpu::multiply_conv(false, dest1, src1, src2);
+ cuda::multiply_conv(false, dest2, src1, src2);
+ DLIB_TEST(max(abs(mat(dest1)-mat(dest2))) < 1e-5);
+ cpu::multiply_conv(true, dest1, src1, src2);
+ cuda::multiply_conv(true, dest2, src1, src2);
+ DLIB_TEST(max(abs(mat(dest1)-mat(dest2))) < 1e-5);
+
+
+ // now try it using the other mode of multiply_conv
+ src2.copy_size(src1);
+ dest1.set_size(1,src1.k(),1,1);
+ dest2.set_size(1,src1.k(),1,1);
+ trand.fill_uniform(dest1);
+ trand.fill_uniform(dest2);
+ trand.fill_uniform(src1);
+ trand.fill_uniform(src2);
+ cpu::multiply_conv(false, dest1, src1, src2);
+ cuda::multiply_conv(false, dest2, src1, src2);
+ float scale = max(abs(mat(dest1)));
+ float scalem = mean(abs(mat(dest1)));
+ DLIB_TEST_MSG(max(abs(mat(dest1)-mat(dest2)))/scale < 1e-4 , max(abs(mat(dest1)-mat(dest2)))/scale);
+ DLIB_TEST_MSG(mean(abs(mat(dest1)-mat(dest2)))/scalem < 1e-5 , mean(abs(mat(dest1)-mat(dest2)))/scalem);
+ matrix<float> prevd2 = mat(dest2);
+ cpu::multiply_conv(false, dest1, src1, src2);
+ cuda::multiply_conv(true, dest2, src1, src2);
+ scale = max(abs(mat(dest1)));
+ scalem = mean(abs(mat(dest1)));
+ DLIB_TEST_MSG(max(abs(mat(dest1)-mat(dest2)+prevd2))/scale < 1e-4 , max(abs(mat(dest1)-mat(dest2)+prevd2))/scale);
+ DLIB_TEST_MSG(mean(abs(mat(dest1)-mat(dest2)+prevd2))/scalem < 1e-5 , mean(abs(mat(dest1)-mat(dest2)+prevd2))/scalem);
+ }
+
+ for (int iter = 0; iter < 100; ++iter)
+ {
+ print_spinner();
+ resizable_tensor dest1, dest2, src, A, B;
+ src.set_size(rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1);
+ dest1.copy_size(src);
+ dest2.copy_size(src);
+ A.set_size(1,src.k(),1,1);
+ B.set_size(1,src.k(),1,1);
+
+ trand.fill_uniform(dest1);
+ trand.fill_uniform(dest2);
+ trand.fill_uniform(src);
+ trand.fill_uniform(A);
+ trand.fill_uniform(B);
+
+ cpu::affine_transform_conv(dest1, src, A, B);
+ cuda::affine_transform_conv(dest2, src, A, B);
+ DLIB_TEST(max(abs(mat(dest1)-mat(dest2))) < 1e-5);
+ }
+
+ for (int iter = 0; iter < 100; ++iter)
+ {
+ print_spinner();
+ resizable_tensor dest1, dest2, g;
+ g.set_size(rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1,
+ rnd.get_random_32bit_number()%30+1);
+ dest1.set_size(1,g.k(),1,1);
+ dest2.set_size(1,g.k(),1,1);
+
+ trand.fill_uniform(dest1);
+ trand.fill_uniform(dest2);
+ trand.fill_uniform(g);
+
+ cpu::assign_conv_bias_gradient(dest1, g);
+ cuda::assign_conv_bias_gradient(dest2, g);
+ const float scale = max(abs(mat(dest1)));
+ const float scalem = mean(abs(mat(dest1)));
+ DLIB_TEST_MSG(max(abs(mat(dest1)-mat(dest2)))/scale < 1e-4 , max(abs(mat(dest1)-mat(dest2)))/scale);
+ DLIB_TEST_MSG(mean(abs(mat(dest1)-mat(dest2)))/scalem < 1e-5 , mean(abs(mat(dest1)-mat(dest2)))/scalem);
+ }
+
+ }
+
+#endif // DLIB_USE_CUDA
+
+// ----------------------------------------------------------------------------------------
+
+ void test_max_pool(
+ const int window_height,
+ const int window_width,
+ const int stride_y,
+ const int stride_x,
+ const int padding_y,
+ const int padding_x
+ )
+ {
+ print_spinner();
+ resizable_tensor A, B, gradient_input;
+ A.set_size(4,5,16,7);
+ B.copy_size(A);
+ gradient_input.copy_size(A);
+
+ tt::tensor_rand rnd;
+ rnd.fill_gaussian(A,0,1);
+ rnd.fill_gaussian(B,0,1);
+ rnd.fill_gaussian(gradient_input,0,1);
+
+
+ tt::pooling mp;
+
+ mp.setup_max_pooling(window_height,window_width,stride_y,stride_x,padding_y,padding_x);
+ mp(A, B);
+
+ // make sure max pooling does what it's spec says it should.
+ DLIB_TEST( A.num_samples() == B.num_samples());
+ DLIB_TEST( A.k() == B.k());
+
+ DLIB_TEST( A.nr() == 1+(B.nr()+2*padding_y-window_height)/stride_y);
+ DLIB_TEST( A.nc() == 1+(B.nc()+2*padding_x-window_width)/stride_x);
+
+ const long x_offset = window_width/2 - padding_x;
+ const long y_offset = window_height/2 - padding_y;
+ for (long s = 0; s < A.num_samples(); ++s)
+ {
+ for (long k = 0; k < A.k(); ++k)
+ {
+ for (long r = 0; r < A.nr(); ++r)
+ {
+ for (long c = 0; c < A.nc(); ++c)
+ {
+ DLIB_TEST_MSG(image_plane(A,s,k)(r,c) == max(subm_clipped(image_plane(B,s,k),
+ centered_rect(c*stride_x+x_offset,
+ r*stride_y+y_offset,
+ window_width,
+ window_height))),
+ "padding: "<< padding_x << " " << padding_y
+ << " window size: " << window_width << " " << window_height
+ << " stride: " << stride_x << " " << stride_y
+ );
+ }
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_avg_pool(
+ const int window_height,
+ const int window_width,
+ const int stride_y,
+ const int stride_x,
+ const int padding_y,
+ const int padding_x
+ )
+ {
+ print_spinner();
+ resizable_tensor A, B, gradient_input;
+ A.set_size(4,5,16,7);
+ B.copy_size(A);
+ gradient_input.copy_size(A);
+
+ tt::tensor_rand rnd;
+ rnd.fill_gaussian(A,0,1);
+ rnd.fill_gaussian(B,0,1);
+ rnd.fill_gaussian(gradient_input,0,1);
+
+
+ tt::pooling mp;
+
+ mp.setup_avg_pooling(window_height,window_width,stride_y,stride_x,padding_y,padding_x);
+ mp(A, B);
+
+ // make sure avg pooling does what it's spec says it should.
+ DLIB_TEST( A.num_samples() == B.num_samples());
+ DLIB_TEST( A.k() == B.k());
+ DLIB_TEST( A.nr() == 1+(B.nr()+2*padding_y-window_height)/stride_y);
+ DLIB_TEST( A.nc() == 1+(B.nc()+2*padding_x-window_width)/stride_x);
+
+ const long x_offset = window_width/2 - padding_x;
+ const long y_offset = window_height/2 - padding_y;
+ for (long s = 0; s < A.num_samples(); ++s)
+ {
+ for (long k = 0; k < A.k(); ++k)
+ {
+ for (long r = 0; r < A.nr(); ++r)
+ {
+ for (long c = 0; c < A.nc(); ++c)
+ {
+ float expected = mean(subm_clipped(image_plane(B,s,k),
+ centered_rect(c*stride_x+x_offset,
+ r*stride_y+y_offset,
+ window_width,
+ window_height)));
+ float err = abs(image_plane(A,s,k)(r,c) - expected);
+ DLIB_TEST_MSG(err < 1e-5, err << " " << expected << " " << image_plane(A,s,k)(r,c));
+ }
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_layers()
+ {
+ {
+ print_spinner();
+ extract_<0,2,2,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ extract_<3,2,1,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ extract_<0,2,1,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ upsample_<1,1> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ upsample_<2,1> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ upsample_<2,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ upsample_<3,3> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ l2normalize_ l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ multiply_ l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ max_pool_<3,3,1,1> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ avg_pool_<3,3,1,1> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ affine_ l(CONV_MODE);
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ affine_ l(FC_MODE);
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ bn_<CONV_MODE> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ bn_<FC_MODE> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ cont_<3,3,3,2,2,0,0> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ cont_<3,3,3,2,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ cont_<3,3,3,1,1> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ cont_<3,3,3,1,1,0,0> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ cont_<3,2,2,2,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ con_<3,2,2,2,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ con_<3,3,3,1,1>l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ con_<3,3,2,1,1> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ con_<2,1,1,1,1> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ con_<3,0,2,2,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ con_<3,2,0,2,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ con_<3,0,0,2,2> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ fc_<1,FC_HAS_BIAS> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ fc_<5,FC_HAS_BIAS> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ fc_<4,FC_NO_BIAS> l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ relu_ l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ prelu_ l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ sig_ l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ htan_ l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ softmax_ l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ {
+ print_spinner();
+ softmax_all_ l;
+ auto res = test_layer(l);
+ DLIB_TEST_MSG(res, res);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <unsigned long n, typename SUBNET> using rcon = max_pool<2,2,2,2,relu<bn_con<con<n,5,5,1,1,SUBNET>>>>;
+ template <unsigned long n, typename SUBNET> using rfc = relu<bn_fc<fc<n,SUBNET>>>;
+
+ void test_tagging(
+ )
+ {
+ typedef loss_multiclass_log<rfc<10,skip1<rfc<84,rfc<120,tag1<rcon<16,rcon<6,input<matrix<unsigned char>>>>>>>>>> net_type;
+
+ net_type net;
+ net_type net2(num_fc_outputs(4));
+
+ DLIB_TEST(layer<tag1>(net).num_computational_layers == 8);
+ DLIB_TEST(layer<skip1>(net).num_computational_layers == 8+3+3);
+ DLIB_TEST(layer<tag1>(net).num_layers == 10);
+ DLIB_TEST(layer<skip1>(net).num_layers == 10+3+3+1);
+ DLIB_TEST(&layer<skip1>(net).get_output() == &layer<tag1>(net).get_output());
+ DLIB_TEST(&layer<skip1>(net).get_output() != &layer<tag1>(net).subnet().subnet().get_output());
+ DLIB_TEST(net.subnet().subnet().subnet().layer_details().get_num_outputs() == 10);
+ DLIB_TEST(net2.subnet().subnet().subnet().layer_details().get_num_outputs() == 4);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ int N,
+ template <typename> class BN,
+ int stride,
+ typename SUBNET
+ >
+ using block = BN<con<N,3,3,1,1,relu<BN<con<N,3,3,stride,stride,SUBNET>>>>>;
+
+ template <
+ template <int,template<typename>class,int,typename> class block,
+ int N,
+ template<typename>class BN,
+ typename SUBNET
+ >
+ using residual = add_prev1<block<N,BN,1,tag1<SUBNET>>>;
+
+ template <
+ template <int,template<typename>class,int,typename> class block,
+ int N,
+ template<typename>class BN,
+ typename SUBNET
+ >
+ using residual_down = add_prev2<avg_pool<2,2,2,2,skip1<tag2<block<N,BN,2,tag1<SUBNET>>>>>>;
+
+
+ template <typename SUBNET> using res = relu<residual<block,8,bn_con,SUBNET>>;
+ template <typename SUBNET> using ares = relu<residual<block,8,affine,SUBNET>>;
+ template <typename SUBNET> using res_down = relu<residual_down<block,8,bn_con,SUBNET>>;
+ template <typename SUBNET> using ares_down = relu<residual_down<block,8,affine,SUBNET>>;
+
+ template <typename SUBNET>
+ using pres = prelu<add_prev1<bn_con<con<8,3,3,1,1,prelu<bn_con<con<8,3,3,1,1,tag1<SUBNET>>>>>>>>;
+
+ void test_visit_funcions()
+ {
+ using net_type2 = loss_multiclass_log<fc<10,
+ avg_pool_everything<
+ pres<res<res<res_down< // 2 prelu layers here
+ tag4<repeat<9,pres, // 9 groups, each containing 2 prelu layers
+ res_down<
+ res<
+ input<matrix<unsigned char>>
+ >>>>>>>>>>>;
+
+ net_type2 pnet;
+
+ DLIB_TEST_MSG(pnet.num_layers == 131, pnet.num_layers);
+ DLIB_TEST_MSG(pnet.num_computational_layers == 109, pnet.num_computational_layers);
+
+ std::vector<bool> hit(pnet.num_computational_layers, false);
+ size_t count = 0;
+ visit_layer_parameter_gradients(pnet, [&](size_t i, tensor& ){hit[i] = true; ++count; });
+ for (auto x : hit)
+ DLIB_TEST(x);
+ DLIB_TEST(count == pnet.num_computational_layers);
+
+ count = 0;
+ std::vector<bool> hit2(pnet.num_computational_layers, false);
+ visit_layer_parameters(pnet, [&](size_t i, tensor& ){hit2[i] = true; ++count; });
+ for (auto x : hit2)
+ DLIB_TEST(x);
+ DLIB_TEST(count == pnet.num_computational_layers);
+ }
+
+ float tensor_read_cpu(const tensor& t, long i, long k, long r, long c)
+ {
+ const float* p = t.host() + t.k() * t.nr() * t.nc() * i +
+ t.nr() * t.nc() * k + t.nc() * r + c;
+ return *p;
+ }
+ void test_copy_tensor_cpu()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor dest(10, 9, 7, 15);
+ resizable_tensor src1(10, 3, 7, 15);
+ resizable_tensor src2(10, 3, 7, 15);
+ resizable_tensor src3(10, 9, 7, 15);
+ tt::tensor_rand rnd;
+ rnd.fill_gaussian(dest);
+ rnd.fill_gaussian(src1);
+ rnd.fill_gaussian(src2);
+ rnd.fill_gaussian(src3);
+
+ cpu::copy_tensor(false, dest, 0, src1, 0, src1.k()); //full copy src1->dest
+ cpu::copy_tensor(false, dest, src1.k(), src2, 0, src2.k()); //full copy src2->dest with offset of src1
+ cpu::copy_tensor(false, dest, src1.k() + src2.k(), src3, 3, 3); //partial copy src3 into the rest place of dest
+
+
+ for (long i = 0; i < dest.num_samples(); ++i)
+ {
+ for (long k = 0; k < dest.k(); ++k)
+ {
+ for (long r = 0; r < dest.nr(); ++r)
+ {
+ for (long c = 0; c < dest.nc(); ++c)
+ {
+ float dest_value = tensor_read_cpu(dest, i, k, r, c);
+ // first part is from src1
+ if (k < src1.k())
+ {
+ float src_value = tensor_read_cpu(src1, i, k, r, c);
+ DLIB_TEST(src_value == dest_value);
+ }
+ // second part is from src2
+ else if (k < src1.k() + src2.k())
+ {
+ float src_value = tensor_read_cpu(src2, i, k - src1.k(), r, c);
+ DLIB_TEST(src_value == dest_value);
+ }
+ // third part is from src3
+ else
+ {
+ float src_value = tensor_read_cpu(src3, i, k - src1.k() - src2.k() + 3, r, c);
+ DLIB_TEST(src_value == dest_value);
+ }
+ }
+ }
+ }
+ }
+ }
+ void test_copy_tensor_add_to_cpu()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor dest(10, 9, 7, 15);
+ resizable_tensor src1(10, 3, 7, 15);
+ resizable_tensor src2(10, 3, 7, 15);
+ resizable_tensor src3(10, 9, 7, 15);
+ tt::tensor_rand rnd;
+ rnd.fill_gaussian(dest);
+ rnd.fill_gaussian(src1);
+ rnd.fill_gaussian(src2);
+ rnd.fill_gaussian(src3);
+
+ const resizable_tensor old_dest = dest;
+
+ cpu::copy_tensor(true, dest, 0, src1, 0, src1.k()); //full copy src1->dest
+ cpu::copy_tensor(true, dest, src1.k(), src2, 0, src2.k()); //full copy src2->dest with offset of src1
+ cpu::copy_tensor(true, dest, src1.k() + src2.k(), src3, 3, 3); //partial copy src3 into the rest place of dest
+
+
+ for (long i = 0; i < dest.num_samples(); ++i)
+ {
+ for (long k = 0; k < dest.k(); ++k)
+ {
+ for (long r = 0; r < dest.nr(); ++r)
+ {
+ for (long c = 0; c < dest.nc(); ++c)
+ {
+ float old_dest_value = tensor_read_cpu(old_dest, i, k, r, c);
+ float dest_value = tensor_read_cpu(dest, i, k, r, c);
+ // first part is from src1
+ if (k < src1.k())
+ {
+ float src_value = tensor_read_cpu(src1, i, k, r, c)+old_dest_value;
+ DLIB_TEST(std::abs(src_value - dest_value) < 1e-6);
+ }
+ // second part is from src2
+ else if (k < src1.k() + src2.k())
+ {
+ float src_value = tensor_read_cpu(src2, i, k - src1.k(), r, c)+old_dest_value;
+ DLIB_TEST(std::abs(src_value - dest_value) < 1e-6);
+ }
+ // third part is from src3
+ else
+ {
+ float src_value = tensor_read_cpu(src3, i, k - src1.k() - src2.k() + 3, r, c)+old_dest_value;
+ DLIB_TEST(std::abs(src_value - dest_value) < 1e-6);
+ }
+ }
+ }
+ }
+ }
+ }
+#ifdef DLIB_USE_CUDA
+ void test_copy_tensor_gpu()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor dest(10, 9, 7, 15);
+ resizable_tensor src1(10, 3, 7, 15);
+ resizable_tensor src2(10, 3, 7, 15);
+ resizable_tensor src3(10, 9, 7, 15);
+ tt::tensor_rand rnd;
+ rnd.fill_gaussian(dest);
+ rnd.fill_gaussian(src1);
+ rnd.fill_gaussian(src2);
+ rnd.fill_gaussian(src3);
+ cuda::copy_tensor(false, dest, 0, src1, 0, src1.k()); //full copy src1->dest
+ cuda::copy_tensor(false, dest, src1.k(), src2, 0, src2.k()); //full copy src2->dest with offset of src1
+ cuda::copy_tensor(false, dest, src1.k() + src2.k(), src3, 3, 3); //partial copy src3 into the rest place of dest
+
+
+ for (long i = 0; i < dest.num_samples(); ++i)
+ {
+ for (long k = 0; k < dest.k(); ++k)
+ {
+ for (long r = 0; r < dest.nr(); ++r)
+ {
+ for (long c = 0; c < dest.nc(); ++c)
+ {
+ float dest_value = tensor_read_cpu(dest, i, k, r, c);
+ // first part is from src1
+ if (k < src1.k())
+ {
+ float src_value = tensor_read_cpu(src1, i, k, r, c);
+ DLIB_TEST(src_value == dest_value);
+ }
+ // second part is from src2
+ else if (k < src1.k() + src2.k())
+ {
+ float src_value = tensor_read_cpu(src2, i, k - src1.k(), r, c);
+ DLIB_TEST(src_value == dest_value);
+ }
+ // third part is from src3
+ else
+ {
+ float src_value = tensor_read_cpu(src3, i, k - src1.k() - src2.k() + 3, r, c);
+ DLIB_TEST(src_value == dest_value);
+ }
+ }
+ }
+ }
+ }
+ }
+ void test_copy_tensor_add_to_gpu()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+ resizable_tensor dest(10, 9, 7, 15);
+ resizable_tensor src1(10, 3, 7, 15);
+ resizable_tensor src2(10, 3, 7, 15);
+ resizable_tensor src3(10, 9, 7, 15);
+ tt::tensor_rand rnd;
+ rnd.fill_gaussian(dest);
+ rnd.fill_gaussian(src1);
+ rnd.fill_gaussian(src2);
+ rnd.fill_gaussian(src3);
+
+ const resizable_tensor old_dest = dest;
+
+ cuda::copy_tensor(true, dest, 0, src1, 0, src1.k()); //full copy src1->dest
+ cuda::copy_tensor(true, dest, src1.k(), src2, 0, src2.k()); //full copy src2->dest with offset of src1
+ cuda::copy_tensor(true, dest, src1.k() + src2.k(), src3, 3, 3); //partial copy src3 into the rest place of dest
+
+
+ for (long i = 0; i < dest.num_samples(); ++i)
+ {
+ for (long k = 0; k < dest.k(); ++k)
+ {
+ for (long r = 0; r < dest.nr(); ++r)
+ {
+ for (long c = 0; c < dest.nc(); ++c)
+ {
+ float old_dest_value = tensor_read_cpu(old_dest, i, k, r, c);
+ float dest_value = tensor_read_cpu(dest, i, k, r, c);
+ // first part is from src1
+ if (k < src1.k())
+ {
+ float src_value = tensor_read_cpu(src1, i, k, r, c)+old_dest_value;
+ DLIB_TEST_MSG(std::abs(src_value - dest_value) < 1e-6, std::abs(src_value - dest_value));
+ }
+ // second part is from src2
+ else if (k < src1.k() + src2.k())
+ {
+ float src_value = tensor_read_cpu(src2, i, k - src1.k(), r, c)+old_dest_value;
+ DLIB_TEST(std::abs(src_value - dest_value) < 1e-6);
+ }
+ // third part is from src3
+ else
+ {
+ float src_value = tensor_read_cpu(src3, i, k - src1.k() - src2.k() + 3, r, c)+old_dest_value;
+ DLIB_TEST(std::abs(src_value - dest_value) < 1e-6);
+ }
+ }
+ }
+ }
+ }
+ }
+#endif//DLIB_USE_CUDA
+
+ template <typename SUBNET> using concat_block1 = con<5,1,1,1,1,SUBNET>;
+ template <typename SUBNET> using concat_block2 = con<8,3,3,1,1,SUBNET>;
+ template <typename SUBNET> using concat_block3 = max_pool<3,3,1,1,SUBNET>;
+ template <typename SUBNET> using concat_incept = inception3<concat_block1,concat_block2,concat_block3,SUBNET>;
+
+ void test_concat()
+ {
+ using namespace dlib::tt;
+ print_spinner();
+
+ using net_type = concat_incept<input<matrix<float>>>;
+
+ resizable_tensor data(10, 1, 111, 222);
+ tt::tensor_rand rnd;
+ rnd.fill_gaussian(data);
+
+ net_type net;
+
+
+ auto& out = net.forward(data);
+
+ auto& b1o = layer<itag1>(net).get_output();
+ auto& b2o = layer<itag2>(net).get_output();
+ auto& b3o = layer<itag3>(net).get_output();
+
+ resizable_tensor dest(10, 14, 111, 222);
+ copy_tensor(false, dest, 0, b1o, 0, b1o.k());
+ copy_tensor(false, dest, b1o.k(), b2o, 0, b2o.k());
+ copy_tensor(false, dest, b1o.k() + b2o.k(), b3o, 0, b3o.k());
+
+ DLIB_TEST(dest.size() == out.size());
+ int error = memcmp(dest.host(), out.host(), dest.size());
+ DLIB_TEST(error == 0);
+
+ resizable_tensor gr(10, 14, 111, 222);
+ rnd.fill_gaussian(gr);
+
+ resizable_tensor params;
+ net.layer_details().backward(gr, net, params);
+
+ auto& b1g = layer<itag1>(net).subnet().get_gradient_input();
+ auto& b2g = layer<itag2>(net).subnet().get_gradient_input();
+ auto& b3g = layer<itag3>(net).subnet().get_gradient_input();
+
+ resizable_tensor g1(10, 5, 111, 222);
+ resizable_tensor g2(10, 8, 111, 222);
+ resizable_tensor g3(10, 1, 111, 222);
+
+ copy_tensor(false, g1, 0, gr, 0, g1.k());
+ copy_tensor(false, g2, 0, gr, g1.k(), g2.k());
+ copy_tensor(false, g3, 0, gr, g1.k() + g2.k(), g3.k());
+ DLIB_TEST(g1.size() == b1g.size());
+ error = memcmp(g1.host(), b1g.host(), b1g.size());
+ DLIB_TEST(error == 0);
+ DLIB_TEST(g2.size() == b2g.size());
+ error = memcmp(g2.host(), b2g.host(), b2g.size());
+ DLIB_TEST(error == 0);
+ DLIB_TEST(g3.size() == b3g.size());
+ error = memcmp(g3.host(), b3g.host(), b3g.size());
+ DLIB_TEST(error == 0);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_simple_linear_regression()
+ {
+ const int num_samples = 1000;
+ ::std::vector<matrix<double>> x(num_samples);
+ ::std::vector<float> y(num_samples);
+ ::std::default_random_engine generator(16);
+ ::std::normal_distribution<float> distribution(0,0.1);
+ const float true_intercept = 50.0;
+ const float true_slope = 10.0;
+ for ( int ii = 0; ii < num_samples; ++ii )
+ {
+ const double val = static_cast<double>(ii)/10;
+ matrix<double> tmp(1,1);
+ tmp = val;
+ x[ii] = tmp;
+ y[ii] = (true_intercept + true_slope*static_cast<float>(val) + distribution(generator));
+ }
+
+ using net_type = loss_mean_squared<fc<1, input<matrix<double>>>>;
+ net_type net;
+ layer<1>(net).layer_details().set_bias_learning_rate_multiplier(300);
+ sgd defsolver(0,0.9);
+ dnn_trainer<net_type> trainer(net, defsolver);
+ trainer.set_learning_rate(1e-5);
+ trainer.set_min_learning_rate(1e-6);
+ trainer.set_mini_batch_size(50);
+ trainer.set_max_num_epochs(170);
+ trainer.train(x, y);
+
+ const float slope = layer<1>(net).layer_details().get_weights().host()[0];
+ const float slope_error = abs(true_slope - slope);
+ const float intercept = layer<1>(net).layer_details().get_biases().host()[0];
+ const float intercept_error = abs(true_intercept - intercept);
+ const float eps_slope = 0.05, eps_intercept = 0.1;
+
+ DLIB_TEST_MSG(slope_error <= eps_slope,
+ "Expected slope = " << true_slope << " Estimated slope = " << slope << " Error limit = " << eps_slope);
+ DLIB_TEST_MSG(intercept_error <= eps_intercept,
+ "Expected intercept = " << true_intercept << " Estimated intercept = " << intercept << " Error limit = " << eps_intercept);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_simple_linear_regression_eil()
+ {
+ print_spinner();
+ const int num_samples = 1000;
+ ::std::vector<matrix<double>> x(num_samples);
+ ::std::vector<float> y(num_samples);
+ ::std::default_random_engine generator(16);
+ ::std::normal_distribution<float> distribution(0,0.0001);
+ const float true_intercept = 50.0;
+ const float true_slope = 10.0;
+ for ( int ii = 0; ii < num_samples; ++ii )
+ {
+ const double val = static_cast<double>(ii)/10;
+ matrix<double> tmp(1,1);
+ tmp = val;
+ x[ii] = tmp;
+ y[ii] = (true_intercept + true_slope*static_cast<float>(val) + distribution(generator));
+ }
+
+ using net_type = loss_epsilon_insensitive<fc<1, input<matrix<double>>>>;
+ net_type net(0.01);
+ layer<1>(net).layer_details().set_bias_learning_rate_multiplier(300);
+ sgd defsolver(0,0.9);
+ dnn_trainer<net_type> trainer(net, defsolver);
+ trainer.set_learning_rate(1e-5);
+ trainer.set_min_learning_rate(1e-8);
+ trainer.set_mini_batch_size(50);
+ trainer.set_max_num_epochs(570);
+ trainer.train(x, y);
+
+ const float slope = layer<1>(net).layer_details().get_weights().host()[0];
+ const float slope_error = abs(true_slope - slope);
+ const float intercept = layer<1>(net).layer_details().get_biases().host()[0];
+ const float intercept_error = abs(true_intercept - intercept);
+ const float eps_slope = 0.01, eps_intercept = 0.1;
+
+ dlog << LINFO << "slope_error: "<< slope_error;
+ dlog << LINFO << "intercept_error: "<< intercept_error;
+ DLIB_TEST_MSG(slope_error <= eps_slope,
+ "Expected slope = " << true_slope << " Estimated slope = " << slope << " Error limit = " << eps_slope);
+ DLIB_TEST_MSG(intercept_error <= eps_intercept,
+ "Expected intercept = " << true_intercept << " Estimated intercept = " << intercept << " Error limit = " << eps_intercept);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_simple_linear_regression_with_mult_prev()
+ {
+ srand(1234);
+ print_spinner();
+ const int num_samples = 1000;
+ ::std::vector<matrix<double>> x(num_samples);
+ ::std::vector<float> y(num_samples);
+ const float true_slope = 2.0;
+ for ( int ii = 0; ii < num_samples; ++ii )
+ {
+ const double val = static_cast<double>(ii-500)/100;
+ matrix<double> tmp(1,1);
+ tmp = val;
+ x[ii] = tmp;
+ y[ii] = ( true_slope*static_cast<float>(val*val));
+ }
+
+ randomize_samples(x,y);
+
+ using net_type = loss_mean_squared<fc<1, mult_prev1<fc<2,tag1<fc<2,input<matrix<double>>>>>>>>;
+ net_type net;
+ sgd defsolver(0,0.9);
+ dnn_trainer<net_type> trainer(net, defsolver);
+ trainer.set_learning_rate(1e-5);
+ trainer.set_min_learning_rate(1e-11);
+ trainer.set_mini_batch_size(50);
+ trainer.set_max_num_epochs(2000);
+ trainer.train(x, y);
+
+ running_stats<double> rs;
+ for (size_t i = 0; i < x.size(); ++i)
+ {
+ double val = y[i];
+ double out = net(x[i]);
+ rs.add(std::abs(val-out));
+ }
+ dlog << LINFO << "rs.mean(): " << rs.mean();
+ dlog << LINFO << "rs.stddev(): " << rs.stddev();
+ dlog << LINFO << "rs.max(): " << rs.max();
+ DLIB_TEST(rs.mean() < 0.1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_multioutput_linear_regression()
+ {
+ const int num_outputs = 2;
+ const int num_samples = 1000;
+ ::std::vector<matrix<double>> x(num_samples);
+ ::std::vector<matrix<float>> y(num_samples);
+ ::std::default_random_engine generator(16);
+ ::std::normal_distribution<float> distribution(0,0.1);
+ ::std::normal_distribution<float> slope_distribution(10,5);
+ ::std::normal_distribution<float> intercept_distribution(50,10);
+ ::std::vector<float> true_intercepts(num_outputs);
+ ::std::vector<float> true_slopes(num_outputs);
+ for ( int jj = 0; jj < num_outputs; ++jj )
+ {
+ true_slopes[jj] = slope_distribution(generator);
+ true_intercepts[jj] = intercept_distribution(generator);
+ }
+ matrix<float> ytmp(num_outputs, 1);
+ for ( int ii = 0; ii < num_samples; ++ii )
+ {
+ const double val = static_cast<double>(ii)/10;
+ matrix<double> tmp(1,1);
+ tmp = val;
+ x[ii] = tmp;
+ for ( int jj = 0; jj < num_outputs; ++jj )
+ ytmp(jj, 0) = (true_intercepts[jj] + true_slopes[jj]*static_cast<float>(val) + distribution(generator));
+
+ y[ii] = ytmp;
+ }
+
+ using net_type = loss_mean_squared_multioutput<fc<num_outputs, input<matrix<double>>>>;
+ net_type net;
+ layer<1>(net).layer_details().set_bias_learning_rate_multiplier(900);
+ sgd defsolver(0,0.9);
+ dnn_trainer<net_type> trainer(net, defsolver);
+ trainer.set_learning_rate(1e-5);
+ trainer.set_min_learning_rate(1e-6);
+ trainer.set_mini_batch_size(50);
+ trainer.set_max_num_epochs(170);
+ trainer.train(x, y);
+
+ float slope_error = 0.0;
+ float intercept_error = 0.0;
+ const float eps_slope = 0.05, eps_intercept = 0.1;
+
+ for ( int jj = 0; jj < num_outputs; ++jj )
+ {
+ slope_error += abs(layer<1>(net).layer_details().get_weights().host()[jj] - true_slopes[jj]);
+ intercept_error += abs(layer<1>(net).layer_details().get_biases().host()[jj] - true_intercepts[jj]);
+ }
+
+ slope_error /= float(num_outputs);
+ intercept_error /= float(num_outputs);
+
+ DLIB_TEST_MSG(slope_error <= eps_slope,
+ "Average absolute slope error = " << slope_error << " Error limit = " << eps_slope);
+ DLIB_TEST_MSG(intercept_error <= eps_intercept,
+ "Average absolute intercept error = " << intercept_error << " Error limit = " << eps_intercept);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_simple_autoencoder()
+ {
+ print_spinner();
+
+ srand(1234);
+
+ const int output_width = 7;
+ const int output_height = 7;
+ const int num_samples = 100;
+ ::std::vector<matrix<float>> x(num_samples);
+
+ matrix<float> tmp(output_width, output_height);
+ for (int i = 0; i < num_samples; ++i)
+ {
+ const int model = i % 4;
+
+ for (int r = 0; r < output_height; ++r)
+ for (int c = 0; c < output_width; ++c)
+ switch (model) {
+ case 0: tmp(r, c) = r / output_height; break;
+ case 1: tmp(r, c) = c / output_width; break;
+ case 2: tmp(r, c) = 1.0 - r / output_height; break;
+ case 3: tmp(r, c) = 1.0 - c / output_width; break;
+ default: DLIB_TEST_MSG(false, "Invalid model: " << model << " (should be between 0 and 3)");
+ }
+
+ x[i] = tmp;
+ }
+
+ using net_type = loss_mean_squared_per_pixel<
+ cont<1,output_height,output_width,2,2,
+ relu<con<4,output_height,output_width,2,2,
+ input<matrix<float>>>>>>;
+ net_type net;
+
+ const auto autoencoder_error = [&x, &net, &output_height, &output_width]()
+ {
+ const auto y = net(x);
+ double error = 0.0;
+ for (size_t i = 0; i < x.size(); ++i)
+ for (int r = 0; r < output_height; ++r)
+ for (int c = 0; c < output_width; ++c)
+ error += fabs(y[i](r, c) - x[i](r, c));
+
+ return error / (x.size() * output_height * output_width);
+ };
+
+ // The autoencoder can't be very good before it's been trained
+ // (or at least the probability of the reconstruction error
+ // being small should be super low; in fact, the error ought to
+ // be much higher than 0.01, however since the initialization
+ // is random, putting the limit below too high could make the
+ // tests fail when other, unrelated tests are added into the
+ // sequence)
+ const double error_before = autoencoder_error();
+ DLIB_TEST_MSG(error_before > 0.01, "Autoencoder error before training = " << error_before);
+
+ // Make sure there's an information bottleneck, as intended
+ const auto& output2 = dlib::layer<2>(net).get_output();
+ DLIB_TEST(output2.nr() == 1);
+ DLIB_TEST(output2.nc() == 1);
+ DLIB_TEST(output2.k() == 4);
+
+ sgd defsolver(0,0.9);
+ dnn_trainer<net_type> trainer(net, defsolver);
+ trainer.set_learning_rate(0.01);
+ trainer.set_max_num_epochs(1000);
+ trainer.train(x, x);
+
+ // Now we should have learned everything there is to it
+ const double error_after = autoencoder_error();
+ DLIB_TEST_MSG(error_after < 1e-6, "Autoencoder error after training = " << error_after);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_loss_multiclass_per_pixel_learned_params_on_trivial_single_pixel_task()
+ {
+ print_spinner();
+
+ constexpr uint16_t num_classes = 7;
+ constexpr uint16_t true_label = num_classes / 2;
+
+ ::std::vector<matrix<float>> x({ matrix<float,1,1>({ 1 }) });
+ ::std::vector<matrix<uint16_t>> y({ matrix<uint16_t,1,1>({ true_label }) });
+
+ using net_type = loss_multiclass_log_per_pixel<con<num_classes,1,1,1,1,input<matrix<float>>>>;
+ net_type net;
+
+ dnn_trainer<net_type> trainer(net, sgd(0,0));
+ trainer.set_learning_rate(1e7);
+ trainer.set_max_num_epochs(1);
+ trainer.train(x, y);
+
+ const tensor& learned_params = layer<1>(net).layer_details().get_layer_params();
+ const float* learned_params_data = learned_params.host();
+
+ for (int is_bias = 0; is_bias <= 1; ++is_bias) {
+ for (uint16_t k = 0; k < num_classes; ++k) {
+ size_t index = k + is_bias * num_classes;
+ DLIB_TEST(index < learned_params.size());
+ if (k == true_label) {
+ DLIB_TEST(learned_params_data[index] > 1e5);
+ }
+ else {
+ DLIB_TEST(learned_params_data[index] < -1e5);
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_loss_multiclass_per_pixel_activations_on_trivial_single_pixel_task()
+ {
+ print_spinner();
+
+ constexpr int input_height = 35;
+ constexpr int input_width = 27;
+ constexpr int output_height = input_height;
+ constexpr int output_width = input_width;
+ constexpr int num_samples = 7;
+ constexpr int num_classes = 5;
+
+ ::std::vector<matrix<float>> x(num_samples);
+ ::std::vector<matrix<uint16_t>> y(num_samples);
+
+ matrix<float> xtmp(input_height, input_width);
+ matrix<uint16_t> ytmp(output_height, output_width);
+
+ ::std::default_random_engine generator(16);
+ ::std::bernoulli_distribution coinflip(0.5);
+
+ using filter_type = con<num_classes,1,1,1,1,input<matrix<float>>>;
+
+ // Define a "truth" filter
+ filter_type truth_filter;
+ truth_filter(xtmp); // Set up the convolutional layer
+
+ // Generate training data
+ for (int ii = 0; ii < num_samples; ++ii) {
+ // Generate random inputs x
+ for (int jj = 0; jj < input_height; ++jj)
+ for (int kk = 0; kk < input_width; ++kk)
+ xtmp(jj, kk) = coinflip(generator) ? 1.f : -1.f;
+ x[ii] = xtmp;
+
+ // Generate target output y by applying the truth filter on x
+ const tensor& output = truth_filter(xtmp);
+ const float* const out_data = output.host();
+
+ const auto out_element = [&](int row, int column, int k) {
+ return out_data[(k * output.nr() + row) * output.nc() + column];
+ };
+
+ for (int jj = 0; jj < output_height; ++jj) {
+ for (int kk = 0; kk < output_width; ++kk) {
+ uint16_t label = 0;
+ float max_value = out_element(jj, kk, 0);
+ for (long k = 1; k < num_classes; ++k) {
+ const float value = out_element(jj, kk, k);
+ if (value > max_value) {
+ label = static_cast<uint16_t>(k);
+ max_value = value;
+ }
+ }
+ ytmp(jj, kk) = label;
+ }
+ }
+ y[ii] = ytmp;
+ }
+
+ using net_type = loss_multiclass_log_per_pixel<filter_type>;
+ net_type net;
+
+ dnn_trainer<net_type> trainer(net, sgd(0,0));
+ trainer.set_learning_rate(1e6);
+ trainer.set_max_num_epochs(1);
+ trainer.train(x, y);
+
+ // Feed forward the training samples.
+ resizable_tensor temp_tensor;
+ net.subnet().to_tensor(&x[0], &x[0] + num_samples, temp_tensor);
+ net.subnet().forward(temp_tensor);
+ const dimpl::subnet_wrapper<filter_type> wsub(net.subnet());
+ const tensor& output_tensor = wsub.get_output();
+ const float* const out_data = output_tensor.host();
+
+ // Let's have a look at the activations before softmax. They should be pretty high
+ // (in terms of absolute value), because the learning task is trivial.
+ for (int ii = 0; ii < num_samples; ++ii) {
+ for (int jj = 0; jj < output_height; ++jj) {
+ for (int kk = 0; kk < output_width; ++kk) {
+ const uint16_t true_label = y[ii](jj, kk);
+
+ for (long k = 0; k < num_classes; ++k) {
+ const size_t index = ((ii * output_tensor.k() + k) * output_tensor.nr() + jj) * output_tensor.nc() + kk;
+ DLIB_TEST(index < output_tensor.size());
+
+ if (k == true_label) {
+ DLIB_TEST(out_data[index] > 1e4);
+ }
+ else {
+ DLIB_TEST(out_data[index] < -1e4);
+ }
+ }
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_loss_multiclass_per_pixel_outputs_on_trivial_task()
+ {
+ print_spinner();
+
+ constexpr int input_height = 7;
+ constexpr int input_width = 5;
+ constexpr int output_height = input_height;
+ constexpr int output_width = input_width;
+ constexpr int num_samples = 7;
+ constexpr int num_classes = 5;
+ constexpr int filter_height = 3;
+ constexpr int filter_width = 3;
+
+ ::std::vector<matrix<float>> x(num_samples);
+ ::std::vector<matrix<uint16_t>> y(num_samples);
+
+ matrix<float> xtmp(input_height, input_width);
+ matrix<uint16_t> ytmp(output_height, output_width);
+
+ ::std::default_random_engine generator(16);
+ ::std::bernoulli_distribution coinflip(0.5);
+
+ using filter_type = con<num_classes, filter_height, filter_width, 1, 1, input<matrix<float>>>;
+
+ // Define a "truth" filter
+ filter_type truth_filter;
+ truth_filter(xtmp); // Set up the convolutional layer
+
+ // Generate training data
+ for (int ii = 0; ii < num_samples; ++ii) {
+ // Generate random inputs x
+ for (int jj = 0; jj < input_height; ++jj)
+ for (int kk = 0; kk < input_width; ++kk)
+ xtmp(jj, kk) = coinflip(generator) ? 1.f : -1.f;
+ x[ii] = xtmp;
+
+ // Generate target output y by applying the truth filter on x
+ const tensor& output = truth_filter(xtmp);
+ const float* const out_data = output.host();
+
+ const auto out_element = [&](int row, int column, int k) {
+ return out_data[(k * output.nr() + row) * output.nc() + column];
+ };
+
+ for (int jj = 0; jj < output_height; ++jj) {
+ for (int kk = 0; kk < output_width; ++kk) {
+ uint16_t label = 0;
+ float max_value = out_element(jj, kk, 0);
+ for (long k = 1; k < num_classes; ++k) {
+ const float value = out_element(jj, kk, k);
+ if (value > max_value) {
+ label = static_cast<uint16_t>(k);
+ max_value = value;
+ }
+ }
+ ytmp(jj, kk) = label;
+ }
+ }
+ y[ii] = ytmp;
+ }
+
+ using net_type = loss_multiclass_log_per_pixel<filter_type>;
+ net_type net;
+
+ dnn_trainer<net_type> trainer(net, sgd(0, 0.9));
+ trainer.set_learning_rate(1);
+ trainer.set_max_num_epochs(2000);
+ trainer.train(x, y);
+
+ // The learning task is separable, so the net should have no problem
+ // getting all the outputs right.
+ DLIB_TEST(net(x) == y);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_loss_multiclass_per_pixel_with_noise_and_pixels_to_ignore()
+ {
+ // "Semantic segmentation" - see https://github.com/davisking/dlib/issues/288
+ // Test learning when some pixels are to be ignored, etc.
+
+ print_spinner();
+
+ constexpr int input_height = 5;
+ constexpr int input_width = 7;
+ constexpr int output_height = input_height;
+ constexpr int output_width = input_width;
+ const int num_samples = 1000;
+ const int num_classes = 6;
+ const double ignore_probability = 0.5;
+ const double noise_probability = 0.05;
+
+ ::std::default_random_engine generator(16);
+ ::std::bernoulli_distribution ignore(ignore_probability);
+ ::std::bernoulli_distribution noise_occurrence(noise_probability);
+ ::std::uniform_int_distribution<uint16_t> noisy_label(0, num_classes - 1);
+
+ ::std::vector<matrix<double>> x(num_samples);
+ ::std::vector<matrix<uint16_t>> y(num_samples);
+
+ ::std::vector<int> truth_histogram(num_classes);
+
+ matrix<double> xtmp(input_height, input_width);
+ matrix<uint16_t> ytmp(output_height, output_width);
+
+ // The function to be learned.
+ const auto ground_truth = [num_classes](const matrix<double>& x, int row, int column) {
+ double sum = 0.0;
+ const int first_column = std::max(0, column - 1);
+ const int last_column = std::min(static_cast<int>(x.nc() - 1), column + 1);
+ for (int c = first_column; c <= last_column; ++c) {
+ sum += x(row, c);
+ }
+ DLIB_TEST(sum < num_classes);
+ return static_cast<uint16_t>(sum);
+ };
+
+ for ( int ii = 0; ii < num_samples; ++ii ) {
+ for ( int jj = 0; jj < input_height; ++jj ) {
+ for ( int kk = 0; kk < input_width; ++kk ) {
+ // Generate numbers between 0 and 2.
+ double value = static_cast<double>(ii + jj + kk) / 10.0;
+ value -= (static_cast<int>(value) / 2) * 2;
+ DLIB_TEST(value >= 0.0 && value < 2.0);
+ xtmp(jj, kk) = value;
+ }
+ }
+ x[ii] = xtmp;
+
+ for ( int jj = 0; jj < output_height; ++jj ) {
+ for ( int kk = 0; kk < output_width; ++kk ) {
+ uint16_t truth = ground_truth(x[ii], jj, kk);
+ DLIB_TEST(truth < num_classes);
+ ++truth_histogram[truth];
+ if (ignore(generator)) {
+ ytmp(jj, kk) = loss_multiclass_log_per_pixel_::label_to_ignore;
+ }
+ else if (noise_occurrence(generator)) {
+ ytmp(jj, kk) = noisy_label(generator);
+ }
+ else {
+ ytmp(jj, kk) = truth;
+ }
+ }
+ }
+
+ y[ii] = ytmp;
+ }
+
+ const int num_total_elements = num_samples * output_height * output_width;
+
+ { // Require a reasonably balanced truth histogram in order to make sure that a trivial classifier is not enough
+ const int required_min_histogram_value = static_cast<int>(::std::ceil(num_total_elements / num_classes * 0.375));
+ for (auto histogram_value : truth_histogram) {
+ DLIB_TEST_MSG(histogram_value >= required_min_histogram_value,
+ "Histogram value = " << histogram_value << ", required = " << required_min_histogram_value);
+ }
+ }
+
+ using net_type = loss_multiclass_log_per_pixel<bn_con<con<num_classes,1,input_width,1,1,input<matrix<double>>>>>;
+ net_type net;
+ sgd defsolver(0,0.9);
+ dnn_trainer<net_type> trainer(net, defsolver);
+ trainer.set_learning_rate(0.1);
+ trainer.set_min_learning_rate(0.01);
+ trainer.set_mini_batch_size(50);
+ trainer.set_max_num_epochs(170);
+ trainer.train(x, y);
+
+ const ::std::vector<matrix<uint16_t>> predictions = net(x);
+
+ int num_correct = 0;
+
+ for ( int ii = 0; ii < num_samples; ++ii ) {
+ const matrix<uint16_t>& prediction = predictions[ii];
+ DLIB_TEST(prediction.nr() == output_height);
+ DLIB_TEST(prediction.nc() == output_width);
+ for ( int jj = 0; jj < output_height; ++jj )
+ for ( int kk = 0; kk < output_width; ++kk )
+ if ( prediction(jj, kk) == ground_truth(x[ii], jj, kk) )
+ ++num_correct;
+ }
+
+ // First some sanity checks.
+ const int num_correct_max = num_total_elements;
+ DLIB_TEST(num_correct_max == ::std::accumulate(truth_histogram.begin(), truth_histogram.end(), 0));
+ DLIB_TEST_MSG(num_correct <= num_correct_max,
+ "Number of correctly classified elements = " << num_correct << ", max = " << num_correct_max);
+
+ // This is the real test, verifying that we have actually learned something.
+ const int num_correct_required = static_cast<int>(::std::ceil(0.9 * num_correct_max));
+ DLIB_TEST_MSG(num_correct >= num_correct_required,
+ "Number of correctly classified elements = " << num_correct << ", required = " << num_correct_required);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_loss_multiclass_per_pixel_weighted()
+ {
+ // Train with pixel-specific weights
+
+ print_spinner();
+
+ constexpr int input_height = 5;
+ constexpr int input_width = 7;
+ constexpr int output_height = input_height;
+ constexpr int output_width = input_width;
+ const int num_samples = 1000;
+ const int num_classes = 6;
+
+ ::std::default_random_engine generator(16);
+ ::std::uniform_real_distribution<double> u01(0.0, 1.0);
+ ::std::uniform_int_distribution<uint16_t> noisy_label(0, num_classes - 1);
+
+ ::std::vector<matrix<double>> x(num_samples);
+ ::std::vector<matrix<uint16_t>> y(num_samples);
+
+ matrix<double> xtmp(input_height, input_width);
+ matrix<uint16_t> ytmp(output_height, output_width);
+
+ // Generate input data
+ for (int ii = 0; ii < num_samples; ++ii) {
+ for (int jj = 0; jj < input_height; ++jj) {
+ for (int kk = 0; kk < input_width; ++kk) {
+ xtmp(jj, kk) = u01(generator);
+ ytmp(jj, kk) = noisy_label(generator);
+ }
+ }
+ x[ii] = xtmp;
+ y[ii] = ytmp;
+ }
+
+ using net_type = loss_multiclass_log_per_pixel_weighted<con<num_classes,1,1,1,1,input<matrix<double>>>>;
+ using weighted_label = loss_multiclass_log_per_pixel_weighted_::weighted_label;
+
+ ::std::vector<matrix<weighted_label>> y_weighted(num_samples);
+
+ for (int weighted_class = 0; weighted_class < num_classes; ++weighted_class) {
+
+ print_spinner();
+
+ // Assign weights
+ for (int ii = 0; ii < num_samples; ++ii) {
+ if (weighted_class == 0) {
+ y_weighted[ii].set_size(input_height, input_width);
+ }
+ for (int jj = 0; jj < input_height; ++jj) {
+ for (int kk = 0; kk < input_width; ++kk) {
+ const uint16_t label = y[ii](jj, kk);
+ const float weight
+ = label == weighted_class
+ ? 1.1f
+ : 0.9f;
+ y_weighted[ii](jj, kk) = weighted_label(label, weight);
+ }
+ }
+ }
+
+ net_type net;
+ sgd defsolver(0,0.9);
+ dnn_trainer<net_type> trainer(net, defsolver);
+ trainer.set_learning_rate(0.1);
+ trainer.set_min_learning_rate(0.01);
+ trainer.set_mini_batch_size(10);
+ trainer.set_max_num_epochs(10);
+ trainer.train(x, y_weighted);
+
+ const ::std::vector<matrix<uint16_t>> predictions = net(x);
+
+ int num_weighted_class = 0;
+ int num_not_weighted_class = 0;
+
+ for ( int ii = 0; ii < num_samples; ++ii ) {
+ const matrix<uint16_t>& prediction = predictions[ii];
+ DLIB_TEST(prediction.nr() == output_height);
+ DLIB_TEST(prediction.nc() == output_width);
+ for ( int jj = 0; jj < output_height; ++jj )
+ for ( int kk = 0; kk < output_width; ++kk )
+ if ( prediction(jj, kk) == weighted_class )
+ ++num_weighted_class;
+ else
+ ++num_not_weighted_class;
+ }
+
+ DLIB_TEST_MSG(num_weighted_class > num_not_weighted_class,
+ "The weighted class (" << weighted_class << ") does not dominate: "
+ << num_weighted_class << " <= " << num_not_weighted_class);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_tensor_resize_bilinear(long samps, long k, long nr, long nc, long onr, long onc)
+ {
+ resizable_tensor img(samps,k,nr,nc);
+ resizable_tensor out(samps,k,onr,onc);
+ resizable_tensor out2(samps,k,onr,onc);
+
+ dlib::rand rnd;
+ for (int iter = 0; iter < 10; ++iter)
+ {
+ print_spinner();
+
+ const size_t idx = rnd.get_random_64bit_number()%img.size();
+
+ img = 1;
+ img.host()[idx] = 2;
+ cpu::resize_bilinear(out, img);
+#ifdef DLIB_USE_CUDA
+ cuda::resize_bilinear(out2, img);
+ DLIB_TEST(max(abs(mat(out)-mat(out2))) < 1e-5);
+#endif
+
+ resizable_tensor gradient_input;
+ gradient_input.copy_size(out);
+ tt::tensor_rand rnd;
+ rnd.fill_uniform(gradient_input);
+
+ const float h = 1e-2;
+
+ img.host()[idx] = 2;
+ cpu::resize_bilinear(out, img);
+ float f1 = dot(out, gradient_input);
+
+ img.host()[idx] = 2+h;
+ cpu::resize_bilinear(out, img);
+ float f2 = dot(out, gradient_input);
+
+ const float numerical_grad = (f2-f1)/h;
+ dlog << LINFO << "numerical grad: " << numerical_grad;
+
+
+ resizable_tensor grad, grad2;
+ grad.copy_size(img);
+ grad = 0.1;
+ grad2.copy_size(img);
+ grad2 = 0.1;
+
+ cpu::resize_bilinear_gradient(grad2, gradient_input);
+ dlog << LINFO << "analytic grad: "<< grad2.host()[idx]-0.1;
+ DLIB_TEST_MSG(std::abs(numerical_grad - grad2.host()[idx]+0.1) < 1e-2, std::abs(numerical_grad - grad2.host()[idx]+0.1) << " numerical_grad: " << numerical_grad);
+
+#ifdef DLIB_USE_CUDA
+ cuda::resize_bilinear_gradient(grad, gradient_input);
+ dlog << LINFO << "analytic grad: "<< grad.host()[idx]-0.1;
+ DLIB_TEST_MSG(std::abs(numerical_grad - grad.host()[idx]+0.1) < 1e-2, std::abs(numerical_grad - grad.host()[idx]+0.1) << " numerical_grad: " << numerical_grad);
+ DLIB_TEST(max(abs(mat(grad)-mat(grad2))) < 1e-5);
+#endif
+
+ }
+
+
+ // now test with strided/sub-window calls
+ alias_tensor aimg(samps, k, nr-2,nc-2);
+ alias_tensor aout(samps, k, onr-2,onc-2);
+ for (int iter = 0; iter < 10; ++iter)
+ {
+ print_spinner();
+
+ const size_t idx = rnd.get_random_64bit_number()%img.size();
+
+ img = 1;
+ img.host()[idx] = 2;
+ out = 9;
+ out2 = 9;
+ auto wout = aout(out, out.nc()*1+1);
+ auto wimg = aimg(img, img.nc()*1+1);
+ cpu::resize_bilinear(wout,out.nc(),out.nr()*out.nc(), wimg,img.nc(),img.nr()*img.nc());
+#ifdef DLIB_USE_CUDA
+ auto wout2 = aout(out2, out2.nc()*1+1);
+ cuda::resize_bilinear(wout2,out2.nc(),out2.nr()*out2.nc(), wimg,img.nc(),img.nr()*img.nc());
+ DLIB_TEST(max(abs(mat(out)-mat(out2))) < 1e-5);
+#endif
+
+
+ resizable_tensor gradient_input;
+ gradient_input.copy_size(out);
+ tt::tensor_rand rnd;
+ rnd.fill_uniform(gradient_input);
+
+ const float h = 1e-2;
+
+ img.host()[idx] = 2;
+ out = 0;
+ wout = aout(out, out.nc()*1+1);
+ wimg = aimg(img, img.nc()*1+1);
+ cpu::resize_bilinear(wout,out.nc(),out.nr()*out.nc(), wimg,img.nc(),img.nr()*img.nc());
+ float f1 = dot(out, gradient_input);
+
+ img.host()[idx] = 2+h;
+ out = 0;
+ cpu::resize_bilinear(wout,out.nc(),out.nr()*out.nc(), wimg,img.nc(),img.nr()*img.nc());
+ float f2 = dot(out, gradient_input);
+
+ const float numerical_grad = (f2-f1)/h;
+ dlog << LINFO << "numerical grad: " << numerical_grad;
+
+
+ resizable_tensor grad, grad2;
+ grad.copy_size(img);
+ grad = 0.1;
+ grad2.copy_size(img);
+ grad2 = 0.1;
+
+ auto wgrad2 = aimg(grad2, grad2.nc()*1+1);
+ auto wgradient_input = aout(gradient_input, gradient_input.nc()*1+1);
+ cpu::resize_bilinear_gradient(wgrad2,grad2.nc(),grad2.nr()*grad2.nc(), wgradient_input,gradient_input.nc(),gradient_input.nr()*gradient_input.nc());
+ dlog << LINFO << "analytic grad: "<< grad2.host()[idx]-0.1;
+ DLIB_TEST_MSG(std::abs(numerical_grad - grad2.host()[idx]+0.1) < 1e-2, std::abs(numerical_grad - grad2.host()[idx]+0.1) << " numerical_grad: " << numerical_grad);
+
+#ifdef DLIB_USE_CUDA
+ wgrad2 = aimg(grad, grad.nc()*1+1);
+ wgradient_input = aout(gradient_input, gradient_input.nc()*1+1);
+ cuda::resize_bilinear_gradient(wgrad2,grad.nc(),grad.nr()*grad.nc(), wgradient_input,gradient_input.nc(),gradient_input.nr()*gradient_input.nc());
+ dlog << LINFO << "analytic grad: "<< grad.host()[idx]-0.1;
+ DLIB_TEST_MSG(std::abs(numerical_grad - grad.host()[idx]+0.1) < 1e-2, std::abs(numerical_grad - grad.host()[idx]+0.1) << " numerical_grad: " << numerical_grad);
+ DLIB_TEST_MSG(max(abs(mat(grad)-mat(grad2))) < 1e-5, max(abs(mat(grad)-mat(grad2))));
+#endif
+
+
+ }
+ }
+
+
+ void test_serialization()
+ {
+ print_spinner();
+
+ using net_type = loss_mean_squared<fc<1, input<matrix<double>>>>;
+ net_type net, net2;
+
+ std::ostringstream out;
+ serialize(net, out);
+ const std::string serialized = out.str();
+ std::istringstream in(serialized);
+ dlib::deserialize(net2, in);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_loss_dot()
+ {
+ print_spinner();
+
+ std::vector<matrix<float,0,1>> samples;
+ std::vector<matrix<float,0,1>> labels;
+
+ const matrix<float> proj = matrix_cast<float>(randm(2,3));
+ for (int i = 0; i < 128; ++i)
+ {
+ // The task is going to be to learn the matrix proj. So we make our
+ // training data thusly:
+ matrix<float,0,1> x = matrix_cast<float>(randm(3,1));
+ matrix<float,0,1> y = normalize(proj*x);
+ samples.push_back(x);
+ labels.push_back(y);
+ }
+
+ using net_type = loss_dot<
+ l2normalize<fc_no_bias<2,
+ input<matrix<float,0,1>>
+ >>>;
+
+ net_type net;
+ dnn_trainer<net_type> trainer(net, sgd(1e-4, 0.9));
+ trainer.set_learning_rate(0.01);
+ trainer.set_min_learning_rate(0.0000001);
+ trainer.set_mini_batch_size(128);
+ trainer.set_max_num_epochs(50000);
+ trainer.train(samples, labels);
+
+
+ for (size_t i = 0; i < samples.size(); ++i)
+ {
+ DLIB_TEST(std::abs(1-dot(net(samples[i]),labels[i])) < 0.001);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_loss_multimulticlass_log()
+ {
+ print_spinner();
+ std::map<string,std::vector<string>> all_labels;
+ all_labels["c1"] = {"a", "b", "c"};
+ all_labels["c2"] = {"d", "e", "f"};
+
+ // make training data
+ std::vector<matrix<float>> samples;
+ std::vector<std::map<string,string>> labels;
+ for (int i = 0; i < 3; ++i)
+ {
+ for (int j = 0; j < 3; ++j)
+ {
+ matrix<float> samp(2,3);
+ samp = 0;
+ samp(0,i) = 1;
+ samp(1,j) = 1;
+ samples.push_back(samp);
+
+ std::map<string,string> l;
+ if (i == 0) l["c1"] = "a";
+ if (i == 1) l["c1"] = "b";
+ if (i == 2) l["c1"] = "c";
+ if (j == 0) l["c2"] = "d";
+ if (j == 1) l["c2"] = "e";
+ if (j == 2) l["c2"] = "f";
+ labels.push_back(l);
+ }
+ }
+
+ using net_type = loss_multimulticlass_log<
+ fc<1,
+ input<matrix<float>>
+ >>;
+
+ net_type net(all_labels);
+ net.subnet().layer_details().set_num_outputs(net.loss_details().number_of_labels());
+
+ dnn_trainer<net_type> trainer(net, sgd(0.1));
+ trainer.set_learning_rate(0.1);
+ trainer.set_min_learning_rate(0.00001);
+ trainer.set_iterations_without_progress_threshold(500);
+
+ trainer.train(samples, labels);
+
+ auto predicted_labels = net(samples);
+
+ // make sure the network predicts the right labels
+ for (size_t i = 0; i < samples.size(); ++i)
+ {
+ DLIB_TEST(predicted_labels[i]["c1"] == labels[i]["c1"]);
+ DLIB_TEST(predicted_labels[i]["c2"] == labels[i]["c2"]);
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class dnn_tester : public tester
+ {
+ public:
+ dnn_tester (
+ ) :
+ tester ("test_dnn",
+ "Runs tests on the deep neural network tools.")
+ {}
+
+ void run_tests (
+ )
+ {
+ // make the tests repeatable
+ srand(1234);
+
+ test_tagging();
+#ifdef DLIB_USE_CUDA
+ test_affine_rect();
+ test_conv();
+ test_more_ops2();
+ test_more_ops(1,1);
+ test_more_ops(3,4);
+ test_more_ops(4,3);
+ test_more_ops(4,1);
+ test_more_ops(1,4);
+ test_more_ops(10000,4);
+ compare_bn_gpu_and_cpu();
+ compare_bn_conv_gpu_and_cpu();
+ test_add();
+ test_multiply_zero_padded();
+ compare_adam();
+ test_copy_tensor_gpu();
+ test_copy_tensor_add_to_gpu();
+ test_scale_channels();
+#endif
+ test_tensor_resize_bilinear(2, 3, 6,6, 11, 11);
+ test_tensor_resize_bilinear(2, 3, 6,6, 3, 4);
+ test_tensor_resize_bilinear(2, 3, 5,6, 12, 21);
+ test_max_pool(1,1,2,3,0,0);
+ test_max_pool(3,3,1,1,0,0);
+ test_max_pool(3,3,2,2,0,0);
+ test_max_pool(2,2,2,2,0,0);
+ test_max_pool(4,5,3,1,0,0);
+ test_avg_pool(1,1,2,3,0,0);
+ test_avg_pool(3,3,1,1,0,0);
+ test_avg_pool(3,3,2,2,0,0);
+ test_avg_pool(2,2,2,2,0,0);
+ test_avg_pool(4,5,3,1,0,0);
+ test_avg_pool(4,4,2,2,0,0);
+ test_avg_pool(4,5,40,50,0,0);
+ test_max_pool(2,2,2,3,1,1);
+ test_max_pool(3,3,1,1,1,1);
+ test_max_pool(3,3,2,2,2,1);
+ test_max_pool(2,2,2,2,1,0);
+ test_max_pool(4,5,3,1,2,3);
+ test_avg_pool(1,1,2,3,0,0);
+ test_avg_pool(3,3,1,1,1,2);
+ test_avg_pool(3,3,2,2,2,1);
+ test_avg_pool(2,2,2,2,1,0);
+ test_avg_pool(4,5,3,1,2,4);
+ test_avg_pool(4,4,2,2,1,3);
+ test_avg_pool(4,5,40,50,0,1);
+ test_tanh();
+ test_softmax();
+ test_softmax_all();
+ test_sigmoid();
+ test_batch_normalize();
+ test_batch_normalize_conv();
+ test_basic_tensor_ops();
+ test_layers();
+ test_visit_funcions();
+ test_copy_tensor_cpu();
+ test_copy_tensor_add_to_cpu();
+ test_concat();
+ test_simple_linear_regression();
+ test_simple_linear_regression_eil();
+ test_simple_linear_regression_with_mult_prev();
+ test_multioutput_linear_regression();
+ test_simple_autoencoder();
+ test_loss_multiclass_per_pixel_learned_params_on_trivial_single_pixel_task();
+ test_loss_multiclass_per_pixel_activations_on_trivial_single_pixel_task();
+ test_loss_multiclass_per_pixel_outputs_on_trivial_task();
+ test_loss_multiclass_per_pixel_with_noise_and_pixels_to_ignore();
+ test_loss_multiclass_per_pixel_weighted();
+ test_serialization();
+ test_loss_dot();
+ test_loss_multimulticlass_log();
+ }
+
+ void perform_test()
+ {
+ dlog << LINFO << "NOW RUNNING TESTS WITH set_dnn_prefer_fastest_algorithms()";
+ set_dnn_prefer_fastest_algorithms();
+ run_tests();
+
+ dlog << LINFO << "NOW RUNNING TESTS WITH set_dnn_prefer_smallest_algorithms()";
+ set_dnn_prefer_smallest_algorithms();
+ run_tests();
+ }
+ } a;
+}
+
+#endif // __INTELLISENSE__
+
diff --git a/ml/dlib/dlib/test/ekm_and_lisf.cpp b/ml/dlib/dlib/test/ekm_and_lisf.cpp
new file mode 100644
index 000000000..b6f410177
--- /dev/null
+++ b/ml/dlib/dlib/test/ekm_and_lisf.cpp
@@ -0,0 +1,306 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm.h>
+#include <dlib/rand.h>
+#include <dlib/string.h>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.ekm_and_lisf");
+
+
+ class empirical_kernel_map_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ empirical_kernel_map_tester (
+ ) :
+ tester (
+ "test_ekm_and_lisf", // the command line argument name for this test
+ "Run tests on the empirical_kernel_map and linearly_independent_subset_finder objects.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ thetime = time(0);
+ }
+
+ time_t thetime;
+ dlib::rand rnd;
+
+ template <typename T>
+ void validate (
+ const T& ekm_small,
+ const T& ekm_big
+ )
+ {
+ matrix<double> tmat;
+ projection_function<typename T::kernel_type> proj;
+
+ ekm_small.get_transformation_to(ekm_big, tmat, proj);
+ DLIB_TEST(tmat.nr() == ekm_big.out_vector_size());
+ DLIB_TEST(tmat.nc() == ekm_small.out_vector_size());
+ DLIB_TEST((unsigned long)proj.basis_vectors.size() == ekm_big.basis_size() - ekm_small.basis_size());
+ for (unsigned long i = 0; i < 6; ++i)
+ {
+ const typename T::sample_type temp = randm(4,1,rnd);
+ DLIB_TEST(length(ekm_big.project(temp) - (tmat*ekm_small.project(temp) + proj(temp))) < 1e-10);
+ }
+ }
+
+
+ void test_transformation_stuff()
+ {
+ typedef matrix<double,0,1> sample_type;
+ typedef radial_basis_kernel<sample_type> kernel_type;
+ const kernel_type kern(1);
+
+
+ for (unsigned long n = 1; n < 6; ++n)
+ {
+ print_spinner();
+ for (unsigned long extra = 1; extra < 10; ++extra)
+ {
+ std::vector<sample_type> samps_small, samps_big;
+ linearly_independent_subset_finder<kernel_type> lisf_small(kern, 1000);
+ linearly_independent_subset_finder<kernel_type> lisf_big(kern, 1000);
+ for (unsigned long i = 0; i < n; ++i)
+ {
+ samps_small.push_back(randm(4,1,rnd));
+ samps_big.push_back(samps_small.back());
+ lisf_big.add(samps_small.back());
+ lisf_small.add(samps_small.back());
+ }
+ for (unsigned long i = 0; i < extra; ++i)
+ {
+ samps_big.push_back(randm(4,1,rnd));
+ lisf_big.add(samps_big.back());
+ }
+
+
+ // test no lisf
+ {
+ empirical_kernel_map<kernel_type> ekm_small, ekm_big;
+ ekm_small.load(kern, samps_small);
+ ekm_big.load(kern, samps_big);
+
+ validate(ekm_small, ekm_big);
+ }
+
+ // test with lisf
+ {
+ empirical_kernel_map<kernel_type> ekm_small, ekm_big;
+ ekm_small.load(lisf_small);
+ ekm_big.load(lisf_big);
+
+ validate(ekm_small, ekm_big);
+ }
+
+ // test with partly lisf
+ {
+ empirical_kernel_map<kernel_type> ekm_small, ekm_big;
+ ekm_small.load(kern, samps_small);
+ ekm_big.load(lisf_big);
+
+ validate(ekm_small, ekm_big);
+ }
+
+ // test with partly lisf
+ {
+ empirical_kernel_map<kernel_type> ekm_small, ekm_big;
+ ekm_small.load(lisf_small);
+ ekm_big.load(kern, samps_big);
+
+ validate(ekm_small, ekm_big);
+ }
+
+ }
+ }
+
+
+ // test what happens if the bigger ekm only has repeated basis vectors
+ {
+ empirical_kernel_map<kernel_type> ekm_big, ekm_small;
+ std::vector<sample_type> samps_big, samps_small;
+
+ sample_type temp = randm(4,1,rnd);
+
+ samps_small.push_back(temp);
+ samps_big.push_back(temp);
+ samps_big.push_back(temp);
+
+ ekm_big.load(kern, samps_big);
+ ekm_small.load(kern, samps_small);
+
+ validate(ekm_small, ekm_big);
+
+ }
+ {
+ empirical_kernel_map<kernel_type> ekm_big, ekm_small;
+ linearly_independent_subset_finder<kernel_type> lisf_small(kern, 1000);
+ std::vector<sample_type> samps_big;
+
+ sample_type temp = randm(4,1,rnd);
+
+ lisf_small.add(temp);
+ samps_big.push_back(temp);
+ samps_big.push_back(temp);
+
+ ekm_big.load(kern, samps_big);
+ ekm_small.load(lisf_small);
+
+ validate(ekm_small, ekm_big);
+
+ }
+ {
+ empirical_kernel_map<kernel_type> ekm_big, ekm_small;
+ std::vector<sample_type> samps_big, samps_small;
+
+ sample_type temp = randm(4,1,rnd);
+ sample_type temp2 = randm(4,1,rnd);
+
+ samps_small.push_back(temp);
+ samps_small.push_back(temp2);
+ samps_big.push_back(temp);
+ samps_big.push_back(temp2);
+ samps_big.push_back(randm(4,1,rnd));
+
+ ekm_big.load(kern, samps_big);
+ ekm_small.load(kern, samps_small);
+
+ validate(ekm_small, ekm_big);
+
+ }
+ {
+ empirical_kernel_map<kernel_type> ekm_big, ekm_small;
+ linearly_independent_subset_finder<kernel_type> lisf_small(kern, 1000);
+ std::vector<sample_type> samps_big;
+
+ sample_type temp = randm(4,1,rnd);
+ sample_type temp2 = randm(4,1,rnd);
+
+ lisf_small.add(temp);
+ lisf_small.add(temp2);
+ samps_big.push_back(temp);
+ samps_big.push_back(temp2);
+ samps_big.push_back(temp);
+
+ ekm_big.load(kern, samps_big);
+ ekm_small.load(lisf_small);
+
+ validate(ekm_small, ekm_big);
+
+ }
+
+
+ }
+
+
+
+ void perform_test (
+ )
+ {
+ ++thetime;
+ typedef matrix<double,0,1> sample_type;
+ //dlog << LINFO << "time seed: " << thetime;
+ //rnd.set_seed(cast_to_string(thetime));
+
+
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+
+ for (int n = 1; n < 10; ++n)
+ {
+ print_spinner();
+ dlog << LINFO << "matrix size " << n;
+
+ std::vector<sample_type> samples;
+ // make some samples
+ for (int i = 0; i < n; ++i)
+ {
+ samples.push_back(randm(4,1,rnd));
+ // double up the samples just to mess with the lisf
+ if (n > 5)
+ samples.push_back(samples.back());
+ }
+
+ dlog << LINFO << "samples.size(): "<< samples.size();
+
+ const kernel_type kern(1);
+
+ linearly_independent_subset_finder<kernel_type> lisf(kern, 100, 1e-4);
+ unsigned long count = 0;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ if (lisf.add(samples[i]))
+ {
+ DLIB_TEST(equal(lisf[lisf.size()-1], samples[i]));
+ ++count;
+ }
+ }
+ DLIB_TEST(count == lisf.size());
+
+ DLIB_TEST(lisf.size() == (unsigned int)n);
+
+
+ dlog << LINFO << "lisf.size(): "<< lisf.size();
+
+ // make sure the kernel matrices coming out of the lisf are correct
+ DLIB_TEST(dlib::equal(lisf.get_kernel_matrix(), kernel_matrix(kern, lisf), 1e-8));
+ DLIB_TEST(dlib::equal(lisf.get_inv_kernel_marix(), inv(kernel_matrix(kern, lisf.get_dictionary())), 1e-8));
+
+ empirical_kernel_map<kernel_type> ekm;
+ ekm.load(lisf);
+ DLIB_TEST(ekm.basis_size() == lisf.size());
+
+ std::vector<sample_type> proj_samples;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ double err;
+ proj_samples.push_back(ekm.project(samples[i], err));
+ DLIB_TEST(err <= 1e-4);
+ const double error_agreement = std::abs(err - lisf.projection_error(samples[i]));
+ dlog << LTRACE << "err: " << err << " error_agreement: "<< error_agreement;
+ DLIB_TEST(error_agreement < 1e-11);
+ }
+
+ for (int i = 0; i < 5; ++i)
+ {
+ sample_type temp = randm(4,1,rnd);
+ double err;
+ ekm.project(temp, err);
+ const double error_agreement = std::abs(err - lisf.projection_error(temp));
+ dlog << LTRACE << "err: " << err << " error_agreement: "<< error_agreement;
+ DLIB_TEST(error_agreement < 1e-11);
+ }
+
+ // make sure the EKM did the projection correctly
+ DLIB_TEST(dlib::equal(kernel_matrix(kern, samples), kernel_matrix(linear_kernel<sample_type>(), proj_samples), 1e-5));
+ }
+
+
+ test_transformation_stuff();
+
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ empirical_kernel_map_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/elastic_net.cpp b/ml/dlib/dlib/test/elastic_net.cpp
new file mode 100644
index 000000000..0e0501639
--- /dev/null
+++ b/ml/dlib/dlib/test/elastic_net.cpp
@@ -0,0 +1,122 @@
+// Copyright (C) 2016 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <dlib/optimization/elastic_net.h>
+#include "tester.h"
+#include <dlib/svm.h>
+#include <dlib/rand.h>
+#include <dlib/string.h>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.elastic_net");
+
+// ----------------------------------------------------------------------------------------
+
+ matrix<double,0,1> basic_elastic_net(
+ const matrix<double>& X,
+ const matrix<double,0,1>& Y,
+ double ridge_lambda,
+ double lasso_budget,
+ double eps
+ )
+ {
+ DLIB_CASSERT(X.nc() == Y.nr(),"");
+
+
+ typedef matrix<double,0,1> sample_type;
+ typedef linear_kernel<sample_type> kernel_type;
+
+ svm_c_linear_dcd_trainer<kernel_type> trainer;
+ trainer.solve_svm_l2_problem(true);
+ const double C = 1/(2*ridge_lambda);
+ trainer.set_c(C);
+ trainer.set_epsilon(eps);
+ trainer.enable_shrinking(true);
+ trainer.include_bias(false);
+
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+ for (long r = 0; r < X.nr(); ++r)
+ {
+ sample_type temp = trans(rowm(X,r));
+
+ const double xmul = (1/lasso_budget);
+ samples.push_back(temp - xmul*Y);
+ labels.push_back(+1);
+ samples.push_back(temp + xmul*Y);
+ labels.push_back(-1);
+ }
+
+ svm_c_linear_dcd_trainer<kernel_type>::optimizer_state state;
+ auto df = trainer.train(samples, labels, state);
+ auto&& alpha = state.get_alpha();
+
+ matrix<double,0,1> betas(alpha.size()/2);
+ for (long i = 0; i < betas.size(); ++i)
+ betas(i) = lasso_budget*(alpha[2*i] - alpha[2*i+1]);
+ betas /= sum(mat(alpha));
+ return betas;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_elastic_net : public tester
+ {
+ public:
+ test_elastic_net (
+ ) :
+ tester (
+ "test_elastic_net",
+ "Run tests on the elastic_net object.",
+ 0
+ )
+ {
+ }
+
+ void perform_test (
+ )
+ {
+ matrix<double> w = {1,2,0,4, 0,0,0,0,0, 6, 7,8,0, 9, 0};
+
+ matrix<double> X = randm(w.size(),1000);
+ matrix<double> Y = trans(X)*w;
+ Y += 0.1*(randm(Y.nr(), Y.nc())-0.5);
+
+
+ double ridge_lambda = 0.1;
+ double lasso_budget = sum(abs(w));
+ double eps = 0.0000001;
+
+ dlib::elastic_net solver(X*trans(X),X*Y);
+ solver.set_epsilon(eps);
+
+
+ matrix<double,0,1> results;
+ matrix<double,0,1> results2;
+ for (double s = 1.2; s > 0.10; s *= 0.9)
+ {
+ print_spinner();
+ dlog << LINFO << "s: "<< s;
+ // make sure the two solvers agree.
+ results = basic_elastic_net(X, Y, ridge_lambda, lasso_budget*s, eps);
+ results2 = solver(ridge_lambda, lasso_budget*s);
+ dlog << LINFO << "error: "<< max(abs(results - results2));
+ DLIB_TEST(max(abs(results - results2)) < 1e-3);
+ }
+ }
+ } a;
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/empirical_kernel_map.cpp b/ml/dlib/dlib/test/empirical_kernel_map.cpp
new file mode 100644
index 000000000..95b085ab3
--- /dev/null
+++ b/ml/dlib/dlib/test/empirical_kernel_map.cpp
@@ -0,0 +1,444 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm.h>
+#include <dlib/rand.h>
+#include <dlib/string.h>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.empirical_kernel_map");
+
+
+ class empirical_kernel_map_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ empirical_kernel_map_tester (
+ ) :
+ tester (
+ "test_empirical_kernel_map", // the command line argument name for this test
+ "Run tests on the empirical_kernel_map object.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ // always use the same time so that tests are repeatable
+ thetime = 0;//time(0);
+ }
+
+ time_t thetime;
+ dlib::rand rnd;
+
+ void test_projection_error()
+ {
+ for (int runs = 0; runs < 10; ++runs)
+ {
+ print_spinner();
+ typedef matrix<double,0,1> sample_type;
+ typedef radial_basis_kernel<sample_type> kernel_type;
+ const kernel_type kern(0.2);
+
+ empirical_kernel_map<kernel_type> ekm;
+
+ // generate samples
+ const int num = rnd.get_random_8bit_number()%50 + 1;
+ std::vector<sample_type> samples;
+ for (int i = 0; i < num; ++i)
+ {
+ samples.push_back(randm(5,1,rnd));
+ }
+
+
+ ekm.load(kern, samples);
+ DLIB_TEST(ekm.basis_size() == samples.size());
+
+ double err;
+
+ // the samples in the basis should have zero projection error
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ ekm.project(samples[i], err);
+ DLIB_TEST_MSG(abs(err) < 1e-13, abs(err));
+
+ }
+
+ // Do some sanity tests on the conversion to distance functions while we are at it.
+ for (int i = 0; i < 30; ++i)
+ {
+ // pick two random samples
+ const sample_type samp1 = samples[rnd.get_random_32bit_number()%samples.size()];
+ const sample_type samp2 = samples[rnd.get_random_32bit_number()%samples.size()];
+
+ const matrix<double,0,1> proj1 = ekm.project(samp1);
+ const matrix<double,0,1> proj2 = ekm.project(samp2);
+
+ distance_function<kernel_type> df1 = ekm.convert_to_distance_function(proj1);
+ distance_function<kernel_type> df2 = ekm.convert_to_distance_function(proj2);
+
+ DLIB_TEST(df1.get_kernel() == kern);
+ DLIB_TEST(df2.get_kernel() == kern);
+
+ // make sure the norms are correct
+ DLIB_TEST(std::abs(df1.get_squared_norm() -
+ trans(df1.get_alpha())*kernel_matrix(df1.get_kernel(),df1.get_basis_vectors())*df1.get_alpha()) < 1e-10);
+ DLIB_TEST(std::abs(df2.get_squared_norm() -
+ trans(df2.get_alpha())*kernel_matrix(df2.get_kernel(),df2.get_basis_vectors())*df2.get_alpha()) < 1e-10);
+
+
+ const double true_dist = std::sqrt(kern(samp1,samp1) + kern(samp2,samp2) - 2*kern(samp1,samp2));
+ DLIB_TEST_MSG(abs(df1(df2) - true_dist) < 1e-7, abs(df1(df2) - true_dist));
+ DLIB_TEST_MSG(abs(length(proj1-proj2) - true_dist) < 1e-7, abs(length(proj1-proj2) - true_dist));
+
+
+ // test distance function operators
+ const decision_function<kernel_type> dec1 = ekm.convert_to_decision_function(proj1);
+ const decision_function<kernel_type> dec2 = ekm.convert_to_decision_function(proj2);
+ DLIB_TEST(dec1.kernel_function == kern);
+ DLIB_TEST(dec2.kernel_function == kern);
+
+ distance_function<kernel_type> temp;
+ temp = dec1;
+ DLIB_TEST(std::abs(temp.get_squared_norm() - df1.get_squared_norm()) < 1e-10);
+ temp = dec2;
+ DLIB_TEST(std::abs(temp.get_squared_norm() - df2.get_squared_norm()) < 1e-10);
+ temp = distance_function<kernel_type>(dec1.alpha, dec1.kernel_function, dec1.basis_vectors);
+ DLIB_TEST(std::abs(temp.get_squared_norm() - df1.get_squared_norm()) < 1e-10);
+
+ df1 = dec1;
+
+ temp = df1 + df2;
+ decision_function<kernel_type> dec3(temp.get_alpha(), 0, temp.get_kernel(), temp.get_basis_vectors());
+ DLIB_TEST(std::abs(temp.get_squared_norm() -
+ trans(temp.get_alpha())*kernel_matrix(temp.get_kernel(),temp.get_basis_vectors())*temp.get_alpha()) < 1e-10);
+ for (unsigned long j = 0; j < samples.size(); ++j)
+ {
+ DLIB_TEST(std::abs(dec3(samples[j]) - (dec1(samples[j]) + dec2(samples[j]))) < 1e-10);
+ }
+
+
+ temp = df1 - df2;
+ dec3 = decision_function<kernel_type>(temp.get_alpha(), 0, temp.get_kernel(), temp.get_basis_vectors());
+ DLIB_TEST(std::abs(temp.get_squared_norm() -
+ trans(temp.get_alpha())*kernel_matrix(temp.get_kernel(),temp.get_basis_vectors())*temp.get_alpha()) < 1e-10);
+ for (unsigned long j = 0; j < samples.size(); ++j)
+ {
+ DLIB_TEST(std::abs(dec3(samples[j]) - (dec1(samples[j]) - dec2(samples[j]))) < 1e-10);
+ }
+
+ temp = 3*(df1 - df2)*2;
+ dec3 = decision_function<kernel_type>(temp.get_alpha(), 0, temp.get_kernel(), temp.get_basis_vectors());
+ DLIB_TEST(std::abs(temp.get_squared_norm() -
+ trans(temp.get_alpha())*kernel_matrix(temp.get_kernel(),temp.get_basis_vectors())*temp.get_alpha()) < 1e-10);
+ for (unsigned long j = 0; j < samples.size(); ++j)
+ {
+ DLIB_TEST(std::abs(dec3(samples[j]) - 6*(dec1(samples[j]) - dec2(samples[j]))) < 1e-10);
+ }
+
+ distance_function<kernel_type> df_empty(kern);
+
+ temp = df_empty + (df1 + df2)/2 + df_empty - df_empty + (df_empty + df_empty) - (df_empty - df_empty);
+ dec3 = decision_function<kernel_type>(temp.get_alpha(), 0, temp.get_kernel(), temp.get_basis_vectors());
+ DLIB_TEST(std::abs(temp.get_squared_norm() -
+ trans(temp.get_alpha())*kernel_matrix(temp.get_kernel(),temp.get_basis_vectors())*temp.get_alpha()) < 1e-10);
+ for (unsigned long j = 0; j < samples.size(); ++j)
+ {
+ DLIB_TEST(std::abs(dec3(samples[j]) - 0.5*(dec1(samples[j]) + dec2(samples[j]))) < 1e-10);
+ }
+ }
+ // Do some sanity tests on the conversion to distance functions while we are at it. This
+ // time multiply one of the projections by 30 and see that it still all works out right.
+ for (int i = 0; i < 30; ++i)
+ {
+ // pick two random samples
+ const sample_type samp1 = samples[rnd.get_random_32bit_number()%samples.size()];
+ const sample_type samp2 = samples[rnd.get_random_32bit_number()%samples.size()];
+
+ matrix<double,0,1> proj1 = ekm.project(samp1);
+ matrix<double,0,1> proj2 = 30*ekm.project(samp2);
+
+ distance_function<kernel_type> df1 = ekm.convert_to_distance_function(proj1);
+ distance_function<kernel_type> df2 = ekm.convert_to_distance_function(proj2);
+
+ DLIB_TEST_MSG(abs(length(proj1-proj2) - df1(df2)) < 1e-7, abs(length(proj1-proj2) - df1(df2)));
+ }
+
+
+ // now generate points with projection error
+ for (double i = 1; i < 10; ++i)
+ {
+ sample_type test_point = i*randm(5,1,rnd);
+ ekm.project(test_point, err);
+ // turn into normal distance rather than squared distance
+ err = sqrt(err);
+ dlog << LTRACE << "projection error: " << err;
+
+ distance_function<kernel_type> df = ekm.convert_to_distance_function(ekm.project(test_point));
+
+ // the projection error should be the distance between the test_point and the point it gets
+ // projected onto
+ DLIB_TEST_MSG(abs(df(test_point) - err) < 1e-10, abs(df(test_point) - err));
+ // while we are at it make sure the squared norm in the distance function is right
+ double df_error = abs(df.get_squared_norm() - trans(df.get_alpha())*kernel_matrix(kern, samples)*df.get_alpha());
+ DLIB_TEST_MSG( df_error < 1e-10, df_error);
+ }
+
+
+
+ }
+ }
+
+ template <typename kernel_type>
+ void test_with_kernel(const kernel_type& kern)
+ {
+ typedef typename kernel_type::sample_type sample_type;
+
+ empirical_kernel_map<kernel_type> ekm, ekm2, ekm3;
+
+ for (int j = 0; j < 10; ++j)
+ {
+ sample_type samp;
+ std::vector<sample_type> samples;
+ std::vector<sample_type> proj_samples;
+ print_spinner();
+ const int num = rnd.get_random_8bit_number()%200 + 1;
+ // make some random samples
+ for (int i = 0; i < num; ++i)
+ {
+ samples.push_back(randm(4,1,rnd));
+ }
+ // add on a little bit to make sure there is at least one non-zero sample. If all the
+ // samples are zero then empirical_kernel_map_error will be thrown and we don't want that.
+ samples.front()(0) += 0.001;
+
+ ekm2.load(kern, samples);
+ DLIB_TEST(ekm2.basis_size() == samples.size());
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ DLIB_TEST(dlib::equal(ekm2[i] , samples[i]));
+
+ // test serialization
+ ostringstream sout;
+ serialize(ekm2, sout);
+ ekm2.clear();
+ istringstream sin(sout.str());
+ deserialize(ekm3, sin);
+ // also test swap
+ ekm3.swap(ekm);
+ DLIB_TEST(ekm.get_kernel() == kern);
+ DLIB_TEST(ekm.out_vector_size() != 0);
+ DLIB_TEST(ekm2.out_vector_size() == 0);
+ DLIB_TEST(ekm3.out_vector_size() == 0);
+
+
+
+ // project all the samples into kernel space
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ proj_samples.push_back(ekm.project(samples[i]));
+ }
+
+ DLIB_TEST(max(abs(kernel_matrix(kern, samples) - kernel_matrix(linear_kernel<sample_type>(), proj_samples))) < 1e-12);
+ DLIB_TEST(ekm.out_vector_size() == proj_samples[0].size());
+
+ for (int i = 0; i < 30; ++i)
+ {
+ const unsigned long idx1 = rnd.get_random_32bit_number()%samples.size();
+ const unsigned long idx2 = rnd.get_random_32bit_number()%samples.size();
+ decision_function<kernel_type> dec_funct = ekm.convert_to_decision_function(proj_samples[idx1]);
+ distance_function<kernel_type> dist_funct = ekm.convert_to_distance_function(proj_samples[idx1]);
+
+ // make sure the distances match
+ const double dist_error = abs(length(proj_samples[idx1] - proj_samples[idx2]) - dist_funct(samples[idx2]));
+ DLIB_TEST_MSG( dist_error < 1e-6, dist_error);
+ // make sure the dot products match
+ DLIB_TEST(abs(dot(proj_samples[idx1],proj_samples[idx2]) - dec_funct(samples[idx2])) < 1e-10);
+
+ // also try the dec_funct with samples that weren't in the original set
+ samp = 100*randm(4,1,rnd);
+ // make sure the dot products match
+ DLIB_TEST(abs(dot(proj_samples[idx1],ekm.project(samp)) - dec_funct(samp)) < 1e-10);
+ samp = randm(4,1,rnd);
+ // make sure the dot products match
+ DLIB_TEST(abs(dot(proj_samples[idx1],ekm.project(samp)) - dec_funct(samp)) < 1e-10);
+ }
+
+
+
+ proj_samples.clear();
+
+
+ // now do the projection but use the projection_function returned by get_projection_function()
+ projection_function<kernel_type> proj2 = ekm.get_projection_function();
+ projection_function<kernel_type> proj;
+ sout.clear();
+ sout.str("");
+ sin.clear();
+ sin.str("");
+ // test serialization
+ serialize(proj2, sout);
+ sin.str(sout.str());
+ deserialize(proj, sin);
+
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ proj_samples.push_back(proj(samples[i]));
+ }
+
+ DLIB_TEST(max(abs(kernel_matrix(kern, samples) - kernel_matrix(linear_kernel<sample_type>(), proj_samples))) < 1e-12);
+ DLIB_TEST(ekm.out_vector_size() == proj_samples[0].size());
+ DLIB_TEST(proj.out_vector_size() == proj_samples[0].size());
+
+ ekm.clear();
+ DLIB_TEST(ekm.out_vector_size() == 0);
+ DLIB_TEST(ekm2.out_vector_size() == 0);
+ DLIB_TEST(ekm3.out_vector_size() == 0);
+
+
+ for (int i = 0; i < 30; ++i)
+ {
+ const unsigned long idx1 = rnd.get_random_32bit_number()%samples.size();
+ const unsigned long idx2 = rnd.get_random_32bit_number()%samples.size();
+ decision_function<kernel_type> dec_funct = convert_to_decision_function(proj,proj_samples[idx1]);
+
+ // make sure the dot products match
+ DLIB_TEST(abs(dot(proj_samples[idx1],proj_samples[idx2]) - dec_funct(samples[idx2])) < 1e-10);
+
+ // also try the dec_funct with samples that weren't in the original set
+ samp = 100*randm(4,1,rnd);
+ // make sure the dot products match
+ DLIB_TEST(abs(dot(proj_samples[idx1],proj(samp)) - dec_funct(samp)) < 1e-10);
+ samp = randm(4,1,rnd);
+ // make sure the dot products match
+ DLIB_TEST(abs(dot(proj_samples[idx1],proj(samp)) - dec_funct(samp)) < 1e-10);
+ }
+
+
+
+
+
+ }
+
+ for (int j = 1; j <= 20; ++j)
+ {
+ dlog << LTRACE << "j: " << j;
+ sample_type samp, samp2;
+ std::vector<sample_type> samples1;
+ std::vector<sample_type> samples2;
+ print_spinner();
+ // make some random samples. At the end samples1 will be a subset of samples2
+ for (int i = 0; i < 5*j; ++i)
+ {
+ samples1.push_back(randm(10,1,rnd));
+ samples2.push_back(samples1.back());
+ }
+ for (int i = 0; i < 5*j; ++i)
+ {
+ samples2.push_back(randm(10,1,rnd));
+ }
+ // add on a little bit to make sure there is at least one non-zero sample. If all the
+ // samples are zero then empirical_kernel_map_error will be thrown and we don't want that.
+ samples1.front()(0) += 0.001;
+ samples2.front()(0) += 0.001;
+
+ ekm.load(kern, samples1);
+ for (unsigned long i = 0; i < samples1.size(); ++i)
+ DLIB_TEST(dlib::equal(ekm[i] , samples1[i]));
+ DLIB_TEST(ekm.basis_size() == samples1.size());
+ ekm2.load(kern, samples2);
+ DLIB_TEST(ekm2.basis_size() == samples2.size());
+
+ dlog << LTRACE << "ekm.out_vector_size(): " << ekm.out_vector_size();
+ dlog << LTRACE << "ekm2.out_vector_size(): " << ekm2.out_vector_size();
+ const double eps = 1e-6;
+
+ matrix<double> transform;
+ // Make sure transformations back to yourself work right. Note that we can't just
+ // check that transform is the identity matrix since it might be an identity transform
+ // for only a subspace of vectors (this happens if the ekm maps points into a subspace of
+ // all possible ekm.out_vector_size() vectors).
+ transform = ekm.get_transformation_to(ekm);
+ DLIB_TEST(transform.nr() == ekm.out_vector_size());
+ DLIB_TEST(transform.nc() == ekm.out_vector_size());
+ for (unsigned long i = 0; i < samples1.size(); ++i)
+ {
+ samp = ekm.project(samples1[i]);
+ DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp));
+ samp = ekm.project((samples1[0] + samples1[i])/2);
+ DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp));
+ }
+
+ transform = ekm2.get_transformation_to(ekm2);
+ DLIB_TEST(transform.nr() == ekm2.out_vector_size());
+ DLIB_TEST(transform.nc() == ekm2.out_vector_size());
+ for (unsigned long i = 0; i < samples2.size(); ++i)
+ {
+ samp = ekm2.project(samples2[i]);
+ DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp));
+ samp = ekm2.project((samples2[0] + samples2[i])/2);
+ DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp));
+ //dlog << LTRACE << "mapping error: " << length(samp - transform*samp);
+ }
+
+
+ // now test the transform from ekm to ekm2
+ transform = ekm.get_transformation_to(ekm2);
+ DLIB_TEST(transform.nr() == ekm2.out_vector_size());
+ DLIB_TEST(transform.nc() == ekm.out_vector_size());
+ for (unsigned long i = 0; i < samples1.size(); ++i)
+ {
+ samp = ekm.project(samples1[i]);
+ distance_function<kernel_type> df1 = ekm.convert_to_distance_function(samp);
+ distance_function<kernel_type> df2 = ekm2.convert_to_distance_function(transform*samp);
+ DLIB_TEST_MSG(df1(df2) < eps, df1(df2));
+ //dlog << LTRACE << "mapping error: " << df1(df2);
+
+
+ samp = ekm.project((samples1[0] + samples1[i])/2);
+ df1 = ekm.convert_to_distance_function(samp);
+ df2 = ekm2.convert_to_distance_function(transform*samp);
+ DLIB_TEST_MSG(df1(df2) < eps, df1(df2));
+ }
+
+
+ }
+ }
+
+ void perform_test (
+ )
+ {
+ ++thetime;
+ typedef matrix<double,0,1> sample_type;
+ dlog << LINFO << "time seed: " << thetime;
+ rnd.set_seed(cast_to_string(thetime));
+
+ print_spinner();
+ test_projection_error();
+ print_spinner();
+ dlog << LINFO << "test with linear kernel";
+ test_with_kernel(linear_kernel<sample_type>());
+ print_spinner();
+ dlog << LINFO << "test with rbf kernel";
+ test_with_kernel(radial_basis_kernel<sample_type>(0.2));
+ print_spinner();
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ empirical_kernel_map_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/entropy_coder.cpp b/ml/dlib/dlib/test/entropy_coder.cpp
new file mode 100644
index 000000000..12a9a3305
--- /dev/null
+++ b/ml/dlib/dlib/test/entropy_coder.cpp
@@ -0,0 +1,587 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <cstdlib>
+
+#include <dlib/entropy_encoder.h>
+#include <dlib/entropy_decoder.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.entropy_coder");
+
+ namespace entropy_coder_kernel_test_helpers
+ {
+ template <
+ typename encoder,
+ typename decoder
+ >
+ std::string test (
+ const std::string& input
+ )
+ /*!
+ ensures
+ - encodes the data from in and then tries to decode it and returns
+ "" if it was successfully decoded else it returns the decoded string
+ !*/
+ {
+ ostringstream sout;
+ istringstream sin;
+ istringstream in;
+
+
+ in.str(input);
+
+ const unsigned long max_total = 65535;
+
+
+
+
+ unsigned long counts[256];
+ for (int i = 0; i < 256; ++i)
+ {
+ counts[i] = 1;
+ }
+
+
+ encoder e;
+
+
+
+ DLIB_TEST(e.stream_is_set() == false);
+
+ e.set_stream(sout);
+
+ DLIB_TEST(e.stream_is_set() == true);
+ DLIB_TEST(&e.get_stream() == &sout);
+
+ unsigned char ch;
+
+ unsigned long total = 256;
+
+ while (in.read((char*)&ch,1))
+ {
+ if (total > max_total)
+ {
+ total = 0;
+ for (int j = 0; j<256; ++j)
+ {
+ counts[j] >>= 1;
+ if (counts[j] == 0)
+ counts[j] = 1;
+ total += counts[j];
+
+ }
+ }
+
+ unsigned long low_count = 0;
+ unsigned long high_count;
+ for (int i = 0; i < ch; ++i)
+ low_count += counts[i];
+ high_count = low_count + counts[ch];
+
+ e.encode(low_count,high_count,total);
+
+
+ ++total;
+ counts[ch] += 1;
+ }
+
+ DLIB_TEST(e.stream_is_set() == true);
+ DLIB_TEST(&e.get_stream() == &sout);
+
+
+
+ e.clear();
+
+ DLIB_TEST(e.stream_is_set() == false);
+
+
+ // *****************************************
+
+
+ decoder d;
+
+
+ DLIB_TEST(d.stream_is_set() == false);
+ DLIB_TEST(d.get_target_called() == false);
+
+ sin.str(sout.str());
+ sout.str("");
+
+ d.set_stream(sin);
+
+ DLIB_TEST(d.get_target_called() == false);
+
+ DLIB_TEST(d.stream_is_set() == true);
+ DLIB_TEST(&d.get_stream() == &sin);
+
+ for (int i = 0; i < 256; ++i)
+ {
+ counts[i] = 1;
+ }
+
+ total = 256;
+
+ for (string::size_type i = 0; i < input.size() ; ++i)
+ {
+ if (total > max_total)
+ {
+ total = 0;
+ for (int j = 0; j<256; ++j)
+ {
+ counts[j] >>= 1;
+ if (counts[j] == 0)
+ counts[j] = 1;
+ total += counts[j];
+
+ }
+ }
+
+ DLIB_TEST(d.get_target_called() == false);
+
+ unsigned long target = d.get_target(total);
+
+ DLIB_TEST(target < total);
+
+ DLIB_TEST(d.get_target_called() == true);
+
+
+ unsigned long low_count;
+ unsigned long high_count = 0;
+
+ unsigned long j;
+ for (j = 0; high_count <= target; ++j)
+ {
+ high_count += counts[j];
+ }
+ --j;
+ low_count = high_count - counts[j];
+
+
+ ch = static_cast<unsigned char>(j);
+
+
+ sout.rdbuf()->sputn((char*)&ch,1);
+
+
+
+ d.decode(low_count,high_count);
+ DLIB_TEST(d.get_target_called() == false);
+ ++total;
+ counts[ch] += 1;
+
+ }
+
+ DLIB_TEST(d.stream_is_set() == true);
+ DLIB_TEST(&d.get_stream() == &sin);
+
+ d.clear();
+
+ DLIB_TEST(d.stream_is_set() == false);
+ DLIB_TEST_MSG(sout.str().size() == input.size(),"the test script is buggy");
+
+
+ if (sout.str() == input)
+ return "";
+ else
+ return sout.str();
+
+ }
+
+ }
+
+
+
+
+ template <
+ typename encoder,
+ typename decoder
+ >
+ void entropy_coder_kernel_test (
+ )
+ /*!
+ requires
+ - encoder is an implementation of entropy_encoder/entropy_encoder_kernel_abstract.h
+ - decoder is an implementation of entropy_decoder/entropy_decoder_kernel_abstract.h
+ ensures
+ - runs tests on encoder and decoder for compliance with the specs
+ !*/
+ {
+ using namespace entropy_coder_kernel_test_helpers;
+
+ dlog << LTRACE << 1;
+
+ print_spinner();
+ string temp, temp2;
+
+ srand(static_cast<int>(time(0)));
+
+ for (int k = 0; k < 10000; ++k)
+ {
+ string temp;
+ istringstream sin;
+ ostringstream sout;
+ decoder d;
+ encoder e;
+
+ e.set_stream(sout);
+
+ int num = ::rand() %200;
+ unsigned long total[200];
+ unsigned long high_count[200];
+ unsigned long low_count[200];
+ for (int i = 0; i < num; ++i)
+ {
+ total[i] = ::rand()%256 + 20;
+ high_count[i] = ::rand()%total[i] + 1;
+ low_count[i] = ::rand()%high_count[i];
+
+ e.encode(low_count[i],high_count[i],total[i]);
+ }
+
+ e.clear();
+
+ sout.rdbuf()->sputc('a');
+
+ sin.str(sout.str());
+
+
+ d.set_stream(sin);
+
+
+ for (int i = 0; i < num; ++i)
+ {
+ unsigned long N = d.get_target(total[i]);
+ DLIB_TEST(low_count[i] <= N && N < high_count[i]);
+ d.decode(low_count[i],high_count[i]);
+ }
+
+
+
+
+
+
+ DLIB_TEST_MSG(sin.rdbuf()->sgetc() != EOF,"num: " << num);
+ DLIB_TEST_MSG(sin.rdbuf()->sgetc() == 'a',
+ "sin.rdbuf()->sgetc() == " << (char)sin.rdbuf()->sgetc() <<
+ "\nnum: " << num
+ );
+ DLIB_TEST(sin.rdbuf()->sbumpc() == 'a');
+ DLIB_TEST(sin.rdbuf()->sgetc() == EOF);
+
+ } // for (int k = 0; k < 10000; ++k)
+
+ dlog << LTRACE << 2;
+
+ print_spinner();
+
+ // the point of this block is to make sure that the return value
+ // from decoder.get_target(total) is a always less than total
+ for (int k = 0; k < 20; ++k)
+ {
+ string temp;
+ temp.push_back(static_cast<char>(::rand()&0xff));
+ istringstream sin(temp);
+ decoder d;
+ d.set_stream(sin);
+ unsigned long total = ::rand()%256 + 20;
+ unsigned long target = d.get_target(total);
+ DLIB_TEST(target<total);
+
+ for (int i = 0; i < 30; ++i)
+ {
+ unsigned long high_count = ::rand()%total + 1;
+ unsigned long low_count = ::rand()%high_count;
+ if (high_count <= target)
+ high_count = target+1;
+ if (low_count > target)
+ low_count = target;
+
+ d.decode(low_count,high_count);
+ target = d.get_target(total);
+ DLIB_TEST_MSG(target<total,"target: " << target << " total: " << total);
+ }
+ }
+
+ print_spinner();
+
+
+ dlog << LTRACE << 3;
+
+ for (int k = 0; k < 10; ++k)
+ {
+ unsigned long seed1 = 1064644658, seed2 = 1064543921;
+ //unsigned long seed1 = 1064682621, seed2 = 1064543921;
+
+ // make array be an array with each element in the range 0 to 255
+ // and have the probability of seeing each number in the array
+ // not be the same
+ //seed1 = static_cast<unsigned long>(time(0));
+ srand(seed1 );
+ int array[65536];
+ for (int i = 0; i < 65536; ++i)
+ {
+ array[i] = ::rand()%256;
+ }
+ for (int i = 0; i < 60; ++i)
+ {
+ int idx = ::rand()%65536;
+ int radius = 35;
+ if (idx > radius && idx <65536-radius)
+ {
+ for (int j = idx-radius; j < idx+radius; ++j)
+ array[j] = array[idx];
+ }
+ }
+
+ // test with 3 random strings of length 10000
+ // but use the above array to bias the random numbers
+ for (int j = 0; j < 3; ++j)
+ {
+ print_spinner();
+ temp = "";
+ //seed2 = static_cast<unsigned long>(time(0));
+ srand(seed2 );
+ for ( int i = 0; i < 10000; ++i)
+ {
+ int a = array[::rand()%65536];
+ temp += (unsigned char)a;
+ }
+ string temp2;
+ temp2 = test<encoder,decoder>(temp);
+ if (temp2 != "")
+ {
+
+ int k = 0;
+ DLIB_TEST(temp != temp2);
+ while (temp[k] == temp2[k])++k;
+ }
+
+
+ DLIB_TEST_MSG(temp2 == "","");
+ }
+ }
+
+ print_spinner();
+
+
+ dlog << LTRACE << 4;
+
+
+
+
+ // test with a large string which contains all the same character
+ temp = "eeeeeeeeee";
+ for (int i = 0; i < 13; ++i)
+ {
+ temp = temp + temp;
+ }
+ temp = test<encoder,decoder>(temp);
+ if (temp != "")
+ {
+ // crop off all the e's until we find the part that is messed up
+ string::size_type pos = temp.find_first_not_of("e");
+ temp = temp.substr(pos);
+ }
+ DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\""); /**/
+
+
+ dlog << LTRACE << 5;
+
+ print_spinner();
+
+ temp = "davis";
+ temp = test<encoder,decoder>(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"");
+
+ temp = "";
+ temp = test<encoder,decoder>(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"");
+
+ // test for each single character
+ for ( int i = 0; i <= 255; ++i)
+ {
+ temp = (unsigned char)i;
+ temp = test<encoder,decoder>(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"");
+ }
+
+ dlog << LTRACE << 6;
+
+ // test with a long string with the same thing repeated many times
+ temp = "davis ";
+ for (int i = 0; i < 10; ++i)
+ {
+ temp = temp + temp;
+ }
+ temp = test<encoder,decoder>(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"");
+
+ dlog << LTRACE << 7;
+
+ // test with 10 random strings of length 1000
+ for (int j = 0; j < 10; ++j)
+ {
+ temp = "";
+ srand(static_cast<unsigned int>(time(0)));
+ for ( int i = 0; i < 1000; ++i)
+ {
+ int a = ::rand()%256;
+ temp += (unsigned char)a;
+ }
+ temp = test<encoder,decoder>(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"");
+ }
+
+
+ dlog << LTRACE << 8;
+
+ print_spinner();
+
+ // test with 15 random strings of length 30000
+ for (int j = 0; j < 15; ++j)
+ {
+ print_spinner();
+ temp = "";
+ unsigned long seed = static_cast<unsigned int>(time(0));
+ srand(seed);
+ for ( int i = 0; i < 30000; ++i)
+ {
+ int a = ::rand()%256;
+ temp += (unsigned char)a;
+ }
+ temp = test<encoder,decoder>(temp); DLIB_TEST_MSG(temp == "","seed: " << seed);
+ }
+
+
+ dlog << LTRACE << 9;
+
+ print_spinner();
+
+ // test with a large string which contains all the same character
+ temp = " ";
+ for (int i = 0; i < 10; ++i)
+ {
+ temp = temp + temp;
+ }
+ temp = test<encoder,decoder>(temp);
+ if (temp != "")
+ {
+ // crop off all the spacess until we find the part that is messed up
+ string::size_type pos = temp.find_first_not_of(" ");
+ temp = temp.substr(pos);
+ }
+ DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"");/**/
+
+
+
+
+
+
+ dlog << LTRACE << 10;
+
+
+
+
+
+
+ // test with a large string which contains a bunch of a's followed by a
+ // bunch of z's
+ temp = "aaaaaaaa";
+ temp2 = "zzzzzzzz";
+ for (int i = 0; i < 12; ++i)
+ {
+ temp = temp + temp;
+ temp2 = temp2 + temp2;
+ }
+ temp += temp2;
+ print_spinner();
+ temp = test<encoder,decoder>(temp);
+ DLIB_TEST(temp == "");
+
+
+
+ dlog << LTRACE << 11;
+
+
+
+ }
+
+
+
+
+ class entropy_coder_tester : public tester
+ {
+ public:
+ entropy_coder_tester (
+ ) :
+ tester ("test_entropy_coder",
+ "Runs tests on the entropy_coder component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a 1";
+ entropy_coder_kernel_test<
+ entropy_encoder::kernel_1a,
+ entropy_decoder::kernel_1a
+ >();
+
+ dlog << LINFO << "testing kernel_1a_c 2";
+ entropy_coder_kernel_test<
+ entropy_encoder::kernel_1a_c,
+ entropy_decoder::kernel_1a_c
+ >();
+
+ dlog << LINFO << "testing kernel_1a 3";
+ entropy_coder_kernel_test<
+ entropy_encoder::kernel_2a,
+ entropy_decoder::kernel_2a
+ >();
+
+ dlog << LINFO << "testing kernel_1a_c 4";
+ entropy_coder_kernel_test<
+ entropy_encoder::kernel_2a_c,
+ entropy_decoder::kernel_2a_c
+ >();
+
+ dlog << LINFO << "testing kernel_1a 5";
+ entropy_coder_kernel_test<
+ entropy_encoder::kernel_1a,
+ entropy_decoder::kernel_1a_c
+ >();
+
+ dlog << LINFO << "testing kernel_1a_c 6";
+ entropy_coder_kernel_test<
+ entropy_encoder::kernel_1a_c,
+ entropy_decoder::kernel_1a
+ >();
+
+ dlog << LINFO << "testing kernel_1a 7";
+ entropy_coder_kernel_test<
+ entropy_encoder::kernel_2a,
+ entropy_decoder::kernel_2a_c
+ >();
+
+ dlog << LINFO << "testing kernel_1a_c 8";
+ entropy_coder_kernel_test<
+ entropy_encoder::kernel_2a_c,
+ entropy_decoder::kernel_2a
+ >();
+
+ }
+ } a;
+
+
+
+
+}
+
diff --git a/ml/dlib/dlib/test/entropy_encoder_model.cpp b/ml/dlib/dlib/test/entropy_encoder_model.cpp
new file mode 100644
index 000000000..0276cbe77
--- /dev/null
+++ b/ml/dlib/dlib/test/entropy_encoder_model.cpp
@@ -0,0 +1,198 @@
+// Copyright (C) 2005 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <cstdlib>
+
+#include <dlib/entropy_encoder_model.h>
+#include <dlib/entropy_decoder_model.h>
+#include <dlib/entropy_encoder.h>
+#include <dlib/entropy_decoder.h>
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.entropy_coder_model");
+
+ template <
+ typename ee,
+ typename ed
+ >
+ void entropy_encoder_model_kernel_test (
+ )
+ /*!
+ requires
+ - ee is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
+ the alphabet_size for ee is 256
+ - ed is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
+ the alphabet_size for ed is 256
+ - ee and ed must share the same kernel number
+ ensures
+ - runs tests on ee and ed for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+ srand(static_cast<unsigned int>(time(0)));
+
+ typedef typename ee::entropy_encoder_type ee_type;
+ typedef typename ed::entropy_decoder_type ed_type;
+
+
+
+ {
+
+ ee_type ecoder;
+ ed_type dcoder;
+
+ ee elen(ecoder);
+ ed dlen(dcoder);
+ ee elit(ecoder);
+ ed dlit(dcoder);
+
+
+ istringstream sin;
+ ostringstream sout;
+
+ ecoder.set_stream(sout);
+
+
+ unsigned long temp;
+
+
+ elen.encode(0);
+ elit.encode(9);
+
+ elen.encode(0);
+ elit.encode(0);
+
+ elen.encode(0);
+ elit.encode(4);
+
+ elen.encode(0);
+ elit.encode(0);
+
+ elen.encode(0);
+ elit.encode(2);
+
+ elen.encode(0);
+ elit.encode(0);
+
+
+
+
+
+
+
+ ecoder.clear();
+ sin.str(sout.str());
+ dcoder.set_stream(sin);
+
+
+ dlen.decode(temp);
+ DLIB_TEST(temp == 0);
+ dlit.decode(temp);
+ DLIB_TEST(temp == 9);
+
+ dlen.decode(temp);
+ DLIB_TEST(temp == 0);
+ dlit.decode(temp);
+ DLIB_TEST(temp == 0);
+
+ dlen.decode(temp);
+ DLIB_TEST(temp == 0);
+ dlit.decode(temp);
+ DLIB_TEST(temp == 4);
+
+ dlen.decode(temp);
+ DLIB_TEST(temp == 0);
+ dlit.decode(temp);
+ DLIB_TEST(temp == 0);
+
+ dlen.decode(temp);
+ DLIB_TEST(temp == 0);
+ dlit.decode(temp);
+ DLIB_TEST(temp == 2);
+
+ dlen.decode(temp);
+ DLIB_TEST(temp == 0);
+ dlit.decode(temp);
+ DLIB_TEST(temp == 0);
+
+
+
+
+ }
+
+ }
+
+
+
+
+ class entropy_encoder_model_tester : public tester
+ {
+ public:
+ entropy_encoder_model_tester (
+ ) :
+ tester ("test_entropy_coder_model",
+ "Runs tests on the entropy_encoder_model and entropy_decoder_model components.")
+ {}
+
+ void perform_test (
+ )
+ {
+ typedef entropy_encoder::kernel_2a_c ee;
+ typedef entropy_decoder::kernel_2a_c ed;
+
+ dlog << LINFO << "testing kernel_1a";
+ entropy_encoder_model_kernel_test<
+ entropy_encoder_model<256,ee>::kernel_1a,
+ entropy_decoder_model<256,ed>::kernel_1a>();
+
+ dlog << LINFO << "testing kernel_2a";
+ entropy_encoder_model_kernel_test<
+ entropy_encoder_model<256,ee>::kernel_2a,
+ entropy_decoder_model<256,ed>::kernel_2a>();
+
+ dlog << LINFO << "testing kernel_3a";
+ entropy_encoder_model_kernel_test<
+ entropy_encoder_model<256,ee>::kernel_3a,
+ entropy_decoder_model<256,ed>::kernel_3a>();
+
+ dlog << LINFO << "testing kernel_4a";
+ entropy_encoder_model_kernel_test<
+ entropy_encoder_model<256,ee>::kernel_4a,
+ entropy_decoder_model<256,ed>::kernel_4a>();
+
+ dlog << LINFO << "testing kernel_4b";
+ entropy_encoder_model_kernel_test<
+ entropy_encoder_model<256,ee>::kernel_4b,
+ entropy_decoder_model<256,ed>::kernel_4b>();
+
+ dlog << LINFO << "testing kernel_5a";
+ entropy_encoder_model_kernel_test<
+ entropy_encoder_model<256,ee>::kernel_5a,
+ entropy_decoder_model<256,ed>::kernel_5a>();
+
+ dlog << LINFO << "testing kernel_5c";
+ entropy_encoder_model_kernel_test<
+ entropy_encoder_model<256,ee>::kernel_5c,
+ entropy_decoder_model<256,ed>::kernel_5c>();
+
+ dlog << LINFO << "testing kernel_6a";
+ entropy_encoder_model_kernel_test<
+ entropy_encoder_model<256,ee>::kernel_6a,
+ entropy_decoder_model<256,ed>::kernel_6a>();
+
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/example.cpp b/ml/dlib/dlib/test/example.cpp
new file mode 100644
index 000000000..4cf927159
--- /dev/null
+++ b/ml/dlib/dlib/test/example.cpp
@@ -0,0 +1,72 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+
+// This is called an unnamed-namespace and it has the effect of making everything
+// inside this file "private" so that everything you declare will have static linkage.
+// Thus we won't have any multiply defined symbol errors coming out of the linker when
+// we try to compile the test suite.
+namespace
+{
+ using namespace test;
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.example");
+
+
+ class example_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ example_tester (
+ ) :
+ tester (
+ "test_example", // the command line argument name for this test
+ "Run example tests.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {}
+
+ void perform_test (
+ )
+ {
+ // This message gets logged to the file debug.txt if the user has enabled logging by
+ // supplying the -d option on the command line (and they haven't set the logging level
+ // to something higher than LINFO).
+ dlog << dlib::LINFO << "some message you want to log";
+
+ // This test is considered a success if this function doesn't throw an exception.
+ // So we can use the DLIB_TEST_MSG macro to perform our tests since it throws an
+ // exception containing a message if its first argument is false.
+
+ // make sure 3 is bigger than 2
+ DLIB_TEST_MSG(3 > 2,"This message prints if your compiler doesn't know 3 is bigger than 2");
+
+ // make sure 5 is not equal to 9
+ DLIB_TEST_MSG(5 != 9,"This message prints if your compiler thinks 5 is the same as 9");
+
+ // This is a form of test you can use when you don't care about having a message
+ DLIB_TEST(5 != 8);
+
+ // If your test takes a long time to run you can also call print_spinner()
+ // periodically. This will cause a spinning / character to display on the
+ // console to indicate to the user that your test is still running (rather
+ // than hung)
+ print_spinner();
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ example_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/example_args.cpp b/ml/dlib/dlib/test/example_args.cpp
new file mode 100644
index 000000000..573216c79
--- /dev/null
+++ b/ml/dlib/dlib/test/example_args.cpp
@@ -0,0 +1,75 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+
+// This is called an unnamed-namespace and it has the effect of making everything
+// inside this file "private" so that everything you declare will have static linkage.
+// Thus we won't have any multiply defined symbol errors coming out of the linker when
+// we try to compile the test suite.
+namespace
+{
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.example_args");
+
+ using namespace test;
+
+ class example_args_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+
+ This particular test requires the user to supply a command line
+ argument when they run it.
+ !*/
+ public:
+ example_args_tester (
+ ) :
+ tester (
+ "test_example_args", // the command line argument name for this test
+ "Run example tests with argument.", // the command line argument description
+ 1 // the number of command line arguments for this test
+ )
+ {}
+
+ void perform_test (
+ const std::string& arg
+ )
+ {
+ // This message gets logged to the file debug.txt if the user has enabled logging by
+ // supplying the -d option on the command line (and they haven't set the logging level
+ // to something higher than LINFO).
+ dlog << dlib::LINFO << "some message you want to log";
+ dlog << dlib::LINFO << "the argument passed to this test was " << arg;
+
+ // This test is considered a success if this function doesn't throw an exception.
+ // So we can use the DLIB_TEST_MSG macro to perform our tests since it throws an
+ // exception containing a message if its first argument is false.
+
+ // make sure 3 is bigger than 2
+ DLIB_TEST_MSG(3 > 2,"This message prints if your compiler doesn't know 3 is bigger than 2");
+
+ // make sure 5 is not equal to 9
+ DLIB_TEST_MSG(5 != 9,"This message prints if your compiler thinks 5 is the same as 9");
+
+ // If your test takes a long time to run you can also call print_spinner()
+ // periodically. This will cause a spinning / character to display on the
+ // console to indicate to the user that your test is still running (rather
+ // than hung)
+ print_spinner();
+ }
+
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ example_args_tester a;
+}
+
+
+
diff --git a/ml/dlib/dlib/test/examples/CMakeLists.txt b/ml/dlib/dlib/test/examples/CMakeLists.txt
new file mode 100644
index 000000000..93bd9a139
--- /dev/null
+++ b/ml/dlib/dlib/test/examples/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+# Disable some warnings from gcc when compiling the examples because fixing them would make the
+# examples harder to read.
+if (CMAKE_COMPILER_IS_GNUCXX)
+ add_definitions("-Wno-comment -Wno-unused-parameter")
+endif()
+
+add_subdirectory(../../../examples examples_build)
diff --git a/ml/dlib/dlib/test/face.cpp b/ml/dlib/dlib/test/face.cpp
new file mode 100644
index 000000000..1bb1a94b6
--- /dev/null
+++ b/ml/dlib/dlib/test/face.cpp
@@ -0,0 +1,360 @@
+// Copyright (C) 2014 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/image_processing/frontal_face_detector.h>
+#include <dlib/image_processing.h>
+#include <vector>
+#include <sstream>
+#include <dlib/compress_stream.h>
+#include <dlib/base64.h>
+#include <dlib/image_io.h>
+
+//#include <dlib/gui_widgets.h>
+//#include <dlib/image_processing/render_face_detections.h>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.face");
+
+
+ class face_tester : public tester
+ {
+ public:
+ face_tester (
+ ) :
+ tester (
+ "test_face", // the command line argument name for this test
+ "Run tests on the face detection/landmarking modules.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+
+ void get_test_face_landmark_dataset (
+ dlib::array<array2d<unsigned char> >& images,
+ std::vector<std::vector<full_object_detection> >& objects
+ )
+ {
+ istringstream sin(get_decoded_string());
+ images.resize(1);
+ objects.resize(1);
+ load_dng(images[0], sin);
+ pyramid_up(images[0]);
+ deserialize(objects[0], sin);
+ }
+
+ void perform_test()
+ {
+ print_spinner();
+ dlib::array<array2d<unsigned char> > images;
+ std::vector<std::vector<full_object_detection> > objects;
+ get_test_face_landmark_dataset(images, objects);
+
+ frontal_face_detector detector = get_frontal_face_detector();
+
+ print_spinner();
+ shape_predictor_trainer trainer;
+ trainer.set_tree_depth(2);
+ trainer.set_nu(0.05);
+ //trainer.be_verbose();
+
+ shape_predictor sp = trainer.train(images, objects);
+
+ print_spinner();
+
+ // It should have been able to perfectly fit the data
+ DLIB_TEST(test_shape_predictor(sp, images, objects) == 0);
+
+ print_spinner();
+
+ // While we are here, make sure the default face detector works
+ std::vector<rectangle> dets = detector(images[0]);
+ DLIB_TEST(dets.size() == 3);
+
+
+ /*
+ // visualize the detections
+ std::vector<full_object_detection> shapes;
+ for (unsigned long j = 0; j < dets.size(); ++j)
+ {
+ full_object_detection shape = sp(images[0], dets[j]);
+ shapes.push_back(shape);
+ }
+ image_window win(images[0]);
+ win.add_overlay(render_face_detections(shapes));
+ cin.get();
+ */
+
+ }
+
+
+ // ------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'test_faces.dat'
+ const std::string get_decoded_string()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'test_faces.dat' we want to decode and return.
+ sout << "RFYXmMn7UA64INJ2Umw+YCh5xX6v+y3bqV/1EKP3ZtvdIWxDCoyZ8oJjj/LXTw3PyEMQReTyXO+8";
+ sout << "423ExTTLMRLxc5gEI4PK8vLMVWdRjRKldYfFLisH5qk7o6TxYfRXqmch/t4c53UfsUuJuVMvA+nf";
+ sout << "05tfgx0Z2VgrlMmvKSxX0VHEjQ3ZVqQl0mLeur1qoMRmcPjYA4QJOvcruwyz/hFpVU8snvsri4QA";
+ sout << "hkCrOtvl/iTlLvcWXDM98OXEYLk4vr6z2v73mGGEdbaJFafXOgutY0NRESpJfingJkuZKXNV7fQ8";
+ sout << "F1DmHwFM0Izoc3fUyN7+xtLo2LSEH8uohv79wjxdbm71n5kgHb6cnpYiiCLOgqKrK+qJUJG1/OBB";
+ sout << "9IORGL6SHrogefDg76m4ayil0lE4pQLa1fKhXGqphdxDMyBXHkOpxA356i5Evk7jZb/AqHUu/hQV";
+ sout << "QYOsW20TRhuFfrasrb/Veq10hMZomosAnNb+Uhgnu2Ip4igX6ozJqmCL4NngjEgoXuCA02KzmIqK";
+ sout << "fcslrBjyg7WZnF2w7UZXcHoZ0AVijb/ANPUqvq9H4k5WCFh53pwG6oj+CG5N7EXLzt9UHtillGJH";
+ sout << "S252/dLvzaNxSq0vDP+Y0IvtKhZgIlmX3duu+L7iJUMinE90OXQFzhwCaOM8oP3Mq+Becgto5Vjb";
+ sout << "vv+2xeyrYL9hBfMyPzbBhVWZdaPyI62MGMPjTfmAUmufWm3/Pxey5Jw6MUNX1rfWMXYQTtamdtcE";
+ sout << "XmuFGhLCWbnJN2GtlOWu+S0LdWAziktr0mdovdFZTwKnd2Fuf1VeMMHBCgF5D56UK6/JTXO1gPlj";
+ sout << "VpavizirUH46rHVnGOFZHWarPKymXyrQ/VhFbVBSOi9UGbsMo9sYNYhvFlzSBN5orNoY+5AP+Y2X";
+ sout << "BDw342Vg3YRIZBqaXZ7oOqyDtjFYNf2g7ColnaFrPiYCKg9VQvVQVXvr4Oa6TTryepXylHk11ijw";
+ sout << "xYgjiENTDKVuXPLVrAEWZD6wq5+LGbmj1cgh59XgLErkoliKxVeEv4ktXqceCFK9YWljqJZSBxFj";
+ sout << "T64N945O47Oek591sfRFYrjebJz3kooaaOQ7lm4BWpW64Am/Od0FIkggSzPUgf+jYrnPdH4oqv3d";
+ sout << "NJIXJO8aeCi/WCqgbdgLwpu1MB8cTdbK2TrCbi3sHhQddE6rqZ1XIg25gYTw72q4ZFUHmRrBEgdz";
+ sout << "i2xh7qHevCWC9Ht7HrUcLl35/UCcNck/ftiDa/xN3rBJp+cJCyS9ZXScFbgFKYfBau8Dx+JA3ygU";
+ sout << "pvYbUP29UeK5hXZoQzC74UKw/liapW8GbR3ZPV+59xmw1b7phyApZfODkDLG5lyTB5Co6vIfmqXp";
+ sout << "DSA1I0ZPIk7hJHWtddgvAg6Yv4GhMZs/cn08Z/ZRXYSMw20rA66BeMD+IPFe3MPFPnKsl/qRvXIC";
+ sout << "gTmLcjPQ5naBo/3haQg4TjJCBCErTC2JktJE0vRfm8v+1kEFoycTsRfhDZtjMnqmqSiNO3VSbnbb";
+ sout << "et/mFvCdd9kqBXQ4VaeYdJwORA7/TocC84G91jlfNRhbY2KW9xHXYYwscfaV5DtPWhyJBEimzLsz";
+ sout << "F59UbkO/WOT7HEwJ3p1/ReH6feLrIYwR8OdSeuOUtK2oboodiUmx/if9pyNONd0If9jFGDXvWP/r";
+ sout << "dL6NdRh68swmPyiCn7sAwaUbd7PF7K+jqgk3jMDMaoWE6p+aAFK3H/JxRO7th2XvX57uA+RKoXEq";
+ sout << "LBJrDkoPGbA5Ctj6KUWknMM62HVIO1SjwZH7ROOlCVbHvDd3JTT6TNs2Lj8g78q6WRMnDVV0L9Q7";
+ sout << "S6awjHePvyj9fDn66jpmRxI9TkqNPx0b8tGfOnUoXGKK/WcInBjVd+FYy1SO5FIVZ4JQdiSMgehu";
+ sout << "EU7X2yjbdgCtVg+kY3ZgYcCMM72NLdm7+U+qVxzfY9bNtzLRsEDNFL2wnq3DkbRRiHKHswEugXjG";
+ sout << "fFfzqjU71sDH3gc1dhOQT456XK0zhmV/62+N+oTxrFY2F/ArALeDiR1q1JOrE1UDzU/ezAZVWS/a";
+ sout << "DJ8O9TVZsbOXOU4hAiQ6mR5hh6i5c/zb7jBl6ehNgixrJqguo9PT10P3S6I+IiTG2vHlws4ZoTmz";
+ sout << "7iOj1ICCN6ivwPj5+afYScxPGLVujxWTW8ksey8RjSIbH+N9wUEAJAcZAGXo2UrP93uRkdLt/cvi";
+ sout << "Q4eIONlUrJ79hlo1xyvPmyNw9Ye1zG6epUK+lsXxtUbtX+uX+sDM/Gkr5QUdzzorfa4Mj9vEglQp";
+ sout << "iK5319kTeymqqV25YhNZZsoqCg+eckmoZP21cAHkPYZWAzg4lxhm71EAp+fE67Y44szeCSRNydRh";
+ sout << "mCl0ZGV59wVfUONdohN/9OQJ8gxifHspscrRszBALwCu2FrniGwRMvIi6lD6tb49dmpPlO1y5SEl";
+ sout << "HPF2I271RVx0YwFPprp+2/fzsnKIIhfgTNRVji2tfjHPoge84e5O02Z/cLlg7EzIfr/JK8Xd6mwp";
+ sout << "t3kIofktLqWbnBrr8qEvz2BmHRlEjYlpb6HfbK82ZHiOusVJdhAxRcRIqmImh5wtunlJOXdQqfmg";
+ sout << "8P0TYVDzQlc6ywbKt/VjTsxI4qisabVvVBkW5VsKU4/JONoNj7fgomwfHqryIIZcgc5vPLawnurD";
+ sout << "7JR1LRiTy7+7riDIxKdYtgbTuOnK6tO103XC+5NT07cKydDgtTu1gYoTTgzY+gkK53lX2Swbbme7";
+ sout << "wIFOXRwSK4ntGt4XXuuPbF8gc0T8ez8/tOEXE6Di8Ckj2O3uz2vGM27PQH9YU3Y3YCdcuaHlUIMG";
+ sout << "s7bgx4nM+xMPmS5baTuAHiPAxp3SepeKpHg0on6Bv99NPSDf7nWRcvvd3+/MHhyDfkbzd88GPnkQ";
+ sout << "Y7a91Tlj8RKG6B8W+zzn+SWzTIz5eJcLJCEKN7fXm1YjJjk3Tdi99PZA/K3Ek2k2lcd2oQPXj6fc";
+ sout << "EUs9zy6sZdSjttwsYlZzLW0Rpiscjqs1XNA+2D5UahufMk4AVpnDPqZ/OvmSZIPpTT4r+uQsEZlJ";
+ sout << "BYf6A9riAPhgR68zPz+i+ffpPcgwURCDviqf370nLIqfbDgJSztxXI2MPsHZqypB+VtvuLTq+M2s";
+ sout << "NVdvA6z5J35d3fk8EHVo8/TIWbsSulqnpJvjIHT9GeTV4EvaJo0kh092cFQ3QkbRIIzEqnT/o06z";
+ sout << "/+gqB0fKl93o50EUVzJbz02rPc/4qVaqfSJLg+HEZUg30PB8wQHb2oWqgL1lYDlqrv5plbK2kJm9";
+ sout << "HW9aQfOyX57rBsYi4aljZl5icy/JElsuNanhnTcTvrHQ/9ntw8QqV2PuVesbbaUQSjDRWG6D1uaK";
+ sout << "HSYB/6fvMZ+8hy+gq4d/tMKpoCzgERJjJOU+N0vHpKmyZgE0EGkPJwlgev/oxTJtsQndgrNviPkr";
+ sout << "ub9ZRkS5uM7Jb+1mKztyVWDdtVvxnvgboNayuS5/VdwlbQezQKEiB8I8UWLsgEJiXg9sgjBaFrv8";
+ sout << "3WgtSQmMRyukOnDPWwDskmUyIHKIye1wOY3H1BUuav52tg8gv1+y2CrVVebRm/8MmhJYe/8DpLeo";
+ sout << "1eEAX2SNtZH4VzpZSuAdANtYXgBaNTc0uWtw9Wc8mwo2hTfbu5nVYJ6vlUFP7HH7L+1idfrz832x";
+ sout << "l20/+8EKd8y2f20iP6m1mnKCQ9PUPPhWMfWMkJ21VhKJJDcpKhvQq20O/yqhfxabl+73QZiCS/eR";
+ sout << "E1ih71FN4x+s952FXOakzYlo5Gge1OCgHE0+YVXBSal4fz6Ye1iRG7+XgLxDIx6AGbOfemRQbOzW";
+ sout << "e/8pe0kPqkkS5ogdkCGemb3hKTgGFGXgP9IvJ18VuRDxPSHD1e5THwvULz7V0hUWO4aKx8t8tZIK";
+ sout << "flDB/npEo3L/1jU5rLEuX5KQbxJfEY2V22hND1ohUZdU+Uy6BFZ/hdYzFAUyNdLAFS36wB3XThar";
+ sout << "54CQ0RGIxCCtv5ucI7VQuc46jkk6SEmZV8FUwv79ExsrB+rAlBvhNOrmVA2vmikrb/iZfA6z1hC2";
+ sout << "aj8BGiULdcW0YUiN/TXxoVT0qgh87VjPcOfkj8gTRMF8VGAgRs0HpXVXKZf+ncAOKJ59yu3EsOCp";
+ sout << "vSG5zxDxrUYD7TFxrelev/7Jtan4J8ouFsK8ZA4WmBkbWLDBkKvV09c7Jxfmgt27aVI5uuUBJYb0";
+ sout << "TdKIG6J/JC85GrRedIb/kRaMiTP0Els6jGp3C/B9PQq6HbzSCUEkLE8is+uWnTDOynbgTtUVEGxH";
+ sout << "EKZGBtnPfqgZRDOnZTWMO9Hd9qATpI2qRrgxIvHTUhqD3DQQ37AGTcNsMmj/+mXTBV2vbM9H7Q5K";
+ sout << "APzltdgkGc+hZIL8Fy3CXzzRFlXAEoIcnJ3BKT7AdGg3pEaW1YcX4akaOTDmImZelYTCoTGu1R4Y";
+ sout << "ZD/rRCeiGR9txS9x9/ptvxeD3J8wYOXxDzCkyMQy1io+izFuN4kTd5MW3RlvepWT4FE2hvjyTyV+";
+ sout << "G4F+lcZFjCGmJKguZEzH3Qtww3OTGZqOfL9oADqQsUpEl92hm0uNOPHH6+8gWPZgb3EcCRkWeXaA";
+ sout << "DkTbCC5rV04N6Fg3j27K1v7qkykWB4y61W00dFejgPitoYuln4A8lY9RtIKzJYFfSOKnrAqYGMkn";
+ sout << "PReI5ZneFTiklSL6FkhWHvr5oz4EsAoU3fLWjky27E1CtpFkPKHLGyc2mnf2N7iBMGa8j2ipy9xd";
+ sout << "JwInqdDdGIHR5dUmNAy1A4vyGbOE7qa0ErVy4m3riKkyE0ObQTNoBeYa6CUHwNWCLCbiW2VzRY/H";
+ sout << "s6APvI6QIco+Wu9dx36qklvA6/OfM79BsUACnCRG2yo3bHeTeKMwKIx05RkNNJ76eOhjxOiPJBVR";
+ sout << "K5V+G3SutaRM0hSK0ABS5nfveZmowfJr8nZHRBAPHyIdv0bJW8lSNIRtZtgwm1dl13+eaeAJNpJm";
+ sout << "3eVvhP8c43LG938Bjxs/nfDl5GMzPnyLOIYInIt4wTXCZlRbt6pMXs9IX9/DpUt/AF44b+XQLnUT";
+ sout << "DgJa4In4qREDt58wel1oAGe9xpIqdFNPduUuCo/Ly0XHrBFd3jQFgp0JWZ039GtG2YTHpo8rLfu+";
+ sout << "TiTAmKnFbVZa6dlOzmVDV+53ptJxiWNfNMa2ri/YEFI7BpKi1FZvMfpGBzNmAdZBAt7kaSvIzqdl";
+ sout << "OHMqka3GBbzyW1PusVpj6SWBZ7rsfIFPRdVO4PGcOWSIQ/YlZYXtkV82cw+m4D/ScXdlj0VZBB04";
+ sout << "YfeUz1m8tiWsLdHxIKRI1JcLek5PzCQX33RFmfeqGBEa7q/kCzGiJ0QHiJV07Fxm2NKRUZQIWiJO";
+ sout << "n1roUf9C06IT03Wd0rcSlwG8Ji9SJZOlBEi7B9Vos61eXMEnkcNiRVeOxLaOfqr20XMde4kquqrS";
+ sout << "qZi2ZhNVqokhXNswwMtlMDfWBWWI39q4evlS8c60lQjXg39kyKbyVZOzp6KrJ+xDYUxURb2d/7DZ";
+ sout << "+UpikS9DmbUgWqV1pmx84ARtPp8/5teoBM7qd6sRrpJ1Q4cE4WLQfr/nVnVmSfZVzm6yqlxjGvhQ";
+ sout << "Bwz85XvMn4xjWIRDNnuwyJh7PoXkoacU54idHA4k7B3qeW59MKtXD3hA34qKUqqE0amH1Xzi3W84";
+ sout << "HpL4xT9EoNUPv+ufvo/4Yir/YIMIVuj1BFQACONJWezdbHO7ze7DQrceR9ojpVlkM442CArpnYWZ";
+ sout << "3SR0NRB0PFjJcgA3RPVWW591v7Aw3G7/aUh5OLSZsOoxrnE2Hb8wM4wQXutleUjcUCxdliAbLl/k";
+ sout << "RcLSE+IzpwRpnSo05sBx91Q71Ws9NeS0Pruy03wScuztfv15MPoBmMH4Nc+JhF/iokGM7C4IICOb";
+ sout << "Woffq9KzUSWaIEEO+qaKqfnG7+/bW5U/gDW0xAfvTt0IuXtoJH5/Gq/g/anFdecnyCdBa4C02MFJ";
+ sout << "gLqm9Dyiuh5Hny9bAuE08YxgrfpwOx3nGxQ/MrXwGUNjCxJEz4TkmFt/Z6HmOUhobQ4Xue5rK6gp";
+ sout << "qWkg7gkXJmpNaj40TFnxQ3Fvw7S1UPNcY3vEvskuYXlB6mI16FCa6ApkR3+krkCKokxelBU5eMxx";
+ sout << "+j5Lv8hYzlSlULUJrDOmGRxQ65lOJPmxbuukr6Uaeh3/i5m8GLqJ3EAkeIABkck+sT/OCCS+1hmY";
+ sout << "/wRbadX8sd19GjHTLkZ7jwEss0qQj1LdtcEtqXgtzy7+8NhQv9c4KhxFNZdYDezehZYZuf4+UeHM";
+ sout << "UAPE6+DX+AtKRD5lSwcAEoFID5GLbsLa+gGWzhmn5dfTDvaJrQNYzI6K1f0MBsWxuXu5SM6dRehm";
+ sout << "9FR9es1OnhIFP8bg5uR7lfIEsfAH6ysgkJyylceoooXwE+cALB+IYfk3mIHNuDMbrQxWIMZmS1er";
+ sout << "I45Gz53QPLgcSjH9Z1mzrhaZV3ZiJqrTYETtObMRX0136rNLBCaytijF1H4QBJaNEsuJpHAYQHsC";
+ sout << "ko8cTk8lzMmh+ENtUjLvrG+pEx9FKCPIgUIZrAAM39fWS5uKhFaAPEkfD/FxbEMdM/hjzbQzcMHy";
+ sout << "iYywZCaCYwolzrQtlTIL3I4VqzpUk/vWMIZt/PMK8lUGBDxzELkXNTYepRJ+uR6QZKOU+/LpLk8K";
+ sout << "MD6+BZNl2karSYjx9qDDHuADoiNJbSXLV2NqyJiNyTmdKv8E4e52mVFfetoMp+gpd7vMJaAObPuJ";
+ sout << "A7rUsNjWz+Zho52LXUSUC1G1MdZPRZPMfk/KvNnXZX93P/KaBXTNLlRf4KkRXQdrnmP5KgKFOvIX";
+ sout << "KUMJ7UQtP0koYJl8OsFHG5yX+qI4BOJqVT0eUypXtlW/CHRX51Wl11wIDsTqbi7zEkBu3kFLMfnr";
+ sout << "3MEYcVWthG5Y9KecfsdLtRnQVSFRMEKEn1kpVAb7xqZhwKDqREVs+32AawqNxPdO4JOCC/wW0zzH";
+ sout << "QlJ8KhbcrxKLaygvVOrqaZGeCNTrrRxpG792CtX4OqXdkxpqcPNjhQJXMgSm/OvHJ1sJOrIHYaru";
+ sout << "JPDH/J4e0qg28rlRpN/iY9xc5Q/dMxhoEsv87ehP+MPKF5ByxrWHbNc9IaOiz5BQIQWAc1glXkKc";
+ sout << "oyMgoCbZ1Zss8zJ1+k4NwoC59BpnT4KbZHZP7+MbXZidCSosl1P88yC0vj0BX8MK+8x6PA3X9Zc5";
+ sout << "Sg2OMThc6WRR3oi/DeHePYqJgPtJwhZt7N651llY8/YIJD7pqVEiB8KJGcrjZ9tDuU0MDTkKnrr7";
+ sout << "qhlSl/XFBGq0x9zIfYeBt6k2wgrpE2/FjgziM3YuH/e7jfppGx3S3G4O+yrUuAynknZQ6Opq+Qs1";
+ sout << "PYFZMW8Fj+CPMgXGy/2+JPXULK8vf0hN3FfNDeHiGpuGEVaEBHdZdE3CW8cWwyRSdvQHgPbXwEaL";
+ sout << "pLGxPhgGQlPLK/JvDQhtL7gqS1LQEAER1sleOHoTV5zEpCsKUcvisz0V7TyFozYnzaG0IcfeGysR";
+ sout << "Kx7O4dq05dlnXicv2IrhcCp9+QZSHDL/E/t/SEafxZJu+sIhqknM+Sgx3MAhE/U8KyOANAYy1aPB";
+ sout << "H5Qt5RnDbYuFJXHDG9DfEWWcNP8e2EL1CX0/gncYvIz3b5Ge0gv4hwbV23Xzsi3hOki4A/B44nOd";
+ sout << "fAE3Ao1D16+6XowEVC8gUh+y1TSnYPTtnB30NbrcMhHNaJP0pYzG41gNaMJNjK8SGXSnPKiXrsJ2";
+ sout << "1jsvbLaMTEBdCqw+2lgg/QwEVgUef7JhVNKbQKf/HTtuD50Ofa4PXv37Q92/xnHWHwjbWfeNEZWA";
+ sout << "Y5bqQI/MlWBKWSGFjpoQsfbCzS6P3ieD3ID91DmB7tDjTDYm5Wq6LoHAQzx+tTxiq45Qn5tUg0zx";
+ sout << "7VC8Xh0ygItADoEqXpKUXdfv0o6G4zxjePM4dvyf4NBkh27q1S/aQwQp8UOury2Eunij57XSxaOb";
+ sout << "IFwlFJYC6wtmg6oV0QZAburx8qJMLdIvHyqa5YJJ3HGuHJIyiD+tuxWVxDZSJQ1RedYqBPAiloyy";
+ sout << "Z3j6EJKqNh0kq3c0K/B7gpX0P1ZjOFZUadIbEW6dd8bxl0RuyhzdSUMkn4rWgmx7zPvoOEgXzbK+";
+ sout << "mJmBT9lEaYE4sFkXfZqDCGq66jdc4RrlD4IZbGkXwMeTuHsfLL1hviKSOyJCTbmS5dKZUdWuVk8R";
+ sout << "XFqATzyHHdArHR9RvNa2bQk5b59tODpeKCqECv5DJ5T2ap8u21ctDCJiFCHq3gLfw6IumI1L2m6/";
+ sout << "aPGdZ0d4ZMR9ooQvJuhAODKg0ZsA+LjHTakpfUwHpanPWkCbmhuh3oMC+hMX+AqOi55nr2O5uxRL";
+ sout << "9UwixLBmRa8g3lbgUGdteTTbvZ2ePyzwxhWp1RS+aFJqtORmRMkgB6vRc4SC1CywKwwHoR3RKEj7";
+ sout << "uW6oQyLQqPYevLuBrbO6yn7U6DkU6blGF7jg/2y12MpwYPr8l661YMXXsmVHCVSJ0AsPSGhJ8oL3";
+ sout << "Cqk6DJbpyoN8O1xK4zNE0cToRFMhEBjlim0lg56HtbEHfLkqRwnFqfo6vvK6opxJoShMXDa5jrLH";
+ sout << "GkpmE4DzaGtZ/P397TF3Y12c6lXJFDYWslp4tMskzsy9FdW63kRUvl6Q3UsWj72qGE6r/PGVetJ9";
+ sout << "in33oiVHTjYppFrza0ryzPE02V4uobC3y2DtoG/YK/GJFkhm68O0QKxyuBURMfT4j046fBQAbwUo";
+ sout << "B/Ylsb+srIUK6sIEnnzdJ/8ve3f961Yx5Kywf/9kVZnUz5RoiP/bOWXm6jasSq7LEvX2nT2fweup";
+ sout << "/TI83XIDWd0rFQoGTfuIuXFfLQbXkX4oZpmYLdr0kQAKjFtNB/JYV5PTE7PskJKD/AS6iYLd2pOf";
+ sout << "cEYJxPZWSWUSz+EmRNmeDl3lfch9LD6VXgaxY1xPF0/1uQfU+BBikdVQJPlMzVB9QK17ir6rynim";
+ sout << "CP038a8ctWt5RMBsaJPZr7bieh11aTTW2mC65Y3PYQ8WsXofuw4x3xoXI1S/hGCM2QvmgWq29xHp";
+ sout << "5Jkp/Z5YLaGBGxCHM+QQm4LzggVnhYjlguAbfEmWFapwhzmx1L26gv2q2AUiozn2I7dAh1vDRKD/";
+ sout << "u5XMODPPJE+NTsr5DQz7aIdEwRLZynp1FO+VN71nYDa5G8ruF4v320ocRKm/mQ5uzU4X7w69CLdS";
+ sout << "kmag9jfDGvuolYqCooAts5b7tFIcC3WjlXeLPq5y8HmzY69Z72HrISpq0Fyq4vcZaksLSdpv+Pil";
+ sout << "iUu6Vmti4LYLHYsmue1UgMzL0qqdRMz6XmCPBkUXYDS4oOoQuDcH5iJo9aWRoADapKUHqIUnoR3O";
+ sout << "Vx4h5b2/XtCEb8dNF0ubJ+oZGbAize7SWTGnUCQdpz2wxAWFymc5/5jFxfVU2BKSPhrKRYImgnVU";
+ sout << "8GOms14wCx4wyGuRZY3p9s1uPUBNNjDnJqVg6I+7STXJKrYzeP2gP227k2JE3o9eLehe66hcqaPi";
+ sout << "egdpG5RfPN9X87FtePJ6lPjJ8j0Ysgoa6l+DDUDuEZHp6APIG5miY893oac8uo/r2RgRNVv6vLFo";
+ sout << "8VIFR7IwcLj1zXvwriv/Szw3POh7y8svSb4eGKr1c1/5JTJB58Fcjz0AMm2+rW0Twwb3STxn4SZ6";
+ sout << "nXOyP0btY0VCckovcLoFij3lsl21ZGMdfG9cHVlKL88pg4Ip00QmgcQW3QmBBoCjlPlRVSSsDHGY";
+ sout << "8TBBGLuxJi7NPzU1HNtjG3cnYw0t49og2hjrIbF+6fHb9x0pPtnJZwX7SbBYlk4Z8v84fR7cjC+9";
+ sout << "l6SLvaRgqkTj/aaiiHtC17zaxNhP9wHqXmPUZdKM6xs3vsAF1dYOLPlIv+nmMLBPfravTZDkf3p1";
+ sout << "x56EjPHwT1GULNkLBG8iod/cteD0E0GIZf0g5/o0hfI1t18CMGxfMyeaASZugV3+KL1yOwXD07D0";
+ sout << "lp8iLn8FlYgXOgUO7+OweJcIu1IwkzLSM2aNbnH3VDPlu/Ff8ZHL0jiuxhQAVT6jdWJSUEOf2yiB";
+ sout << "8mIGCK7CH9Xv9l/grSdh6GrE+NvvWqKQrhX1k8wxHEM4PnhMSO4R+5dRFWeeh6cYfTNHTYWZ2xzU";
+ sout << "run1L6tULZzpksLtHYDg0vEEq3hDS/3yf+/cvCX4ibt5pUqorTpAtNvbTaguUyBy2TOAy6fSFGh2";
+ sout << "eHil/3JEYZXnfFtcBo+pIvt3LWEPlWCUHNKFLQnpd77Y6wUFn3Ku7o7Nu7zBxemmvxxYUXImAlzt";
+ sout << "354O5G/5G1GUGFf1K2u11fFcuXrfowEE+1eUEpC0KLyxZhOJa5nA6dKtnQbq8wrGXxuGuJGlDSAu";
+ sout << "0sUYLPmELc+kGUyY6A27B0FKFN50bP1U5iWLAtxt0NmPqOnwzvnj5GYQ9R/ZIpzf73N2OoYL4+ba";
+ sout << "6E32ION5IxY2YQ1IqEHxsjzvDW5KoQCb8oz63eKgwLHBz/1yhA0ELpzG9ti5pVE4WbGKOtS/2xTh";
+ sout << "RIgpnpbB7bPUdtw33cjky7t6UAO+QYI1kg8rscd/Ug44hd627JK61SxnGlK5wBRj7aoUxH2yb3Dt";
+ sout << "jMgmcgZYtdIsHjuU63vrN0acMHULcyCRIFuFEtXgnQNIKjPUG3iuN3714Y9sncW5HqDGAYLyRpaA";
+ sout << "69XPtqYEajN2uLF1Q9KIeW701X1diQoHw7TFq0p5x1oTMRzjqcz5lnLIM0DycqCPGoGAnyL0o5A3";
+ sout << "Rw9qaSq1bB5VOdqpZHyN38huATstlHmcO2GqN2r9k2BKqqDYxuzmhB1K5ugoJID0lm6KfR87e+2q";
+ sout << "CQL1tr6ecqFe4LkO6nRR57w6gl48J0tFYuxsgRcktYvkt/BF1JHNnw/BChE9lDBgBZz8TfAqUv5b";
+ sout << "Ofi4WiuGxq5sKIa8a5SRwfVbz1h/MBqBEd9nDlZ1acbg9ZGakzwCfH0WrcArLiN9FqGqmiZClS0d";
+ sout << "cUwftQDUI7yEoiIb18/479c1VU2q5dJddCBaabm8CtGtd8w8KTANBXX4pZoSuOlYUUQaxYsZ/avm";
+ sout << "RYqfU1uOkHlmqm++EvfKEGW/Rmoq/fCIl4mk7YoLpMcub9wlTSVP2W//uvZG0LYwlZScWGOGmo6Z";
+ sout << "xa02FmCXVIyXUfnitTEv2oYj3CV/57nW4+1jkXTcYhH8wt5wX5G2eO7qw3esj1x1kL07xmven4Il";
+ sout << "nmKMri2FNxrWUBzvCwmfKGfPh1IkQ9LAfaJJATfGeBFI33RQdSILTaozNl88dHbUO8I+ZnySvavV";
+ sout << "uX9Ia4Gvrm0nzV6WYbE4SCDjppsaz0CSZy1exA9t/NFoQFjvf25pszQ9JlDtwDm65ssYqCTLjyoJ";
+ sout << "AjMMUygef0nD9WxtWkVCywmyR5HIZWqwV/poAROWBUNL72p0kYxDsm8u8D6LFDQJj+/rSQFr4jzF";
+ sout << "RkH7zemYp52d7nSo7ZV84Pf11aTTWqg1OCwAFz+bcg5wZObUL48+WzPAPePNtlo2ef4hn3tyi/pj";
+ sout << "v62xZax1oHnnB4ozyZqwSd7aH8LGN4G0Pk37PCagVXLEyLEGQXA3NqxxokimT93xORZOF4hZjhUR";
+ sout << "EM6aKChyS4DKkB/HN8IEMrPcKL7zadhDrWX6aeAxBOIbF02jTyCo7rFEO4g3TLuy+aX29SStyzAd";
+ sout << "bESo1w0hmnjboB/cUVh9SU0rWvyHnBveXBU1QFsmKEpEVXbD9iao+VArYlDKQgXS0elIQIJHLJ2v";
+ sout << "8cVk5GtsXQU9Yd5vyzC9R/ZuUD+fuRcoKYwevCjnVegbn4mCK6VICihqWM5etEr9CqdjjzAtemN3";
+ sout << "RhW/4c1v6Gfcb3LQIctJmk08SbUfkImRlULjt3sr+iF/9gMx5AneRDqnq1YRbiusqAfpCl83zBFm";
+ sout << "/txWD4btmU3/Q9TzIYjcDm8JFIpptv1+F6myuN1ElJPj5dcmfBZ2/KQknRf7cFBSFCfeKS2glsIm";
+ sout << "tTj1p8jK+qKf3GS+v/n6VutWgGXAU7bjZSfaWn3wfNX1rJXOX4Czp1dXxmXuxltVQ09bTpEMQL5o";
+ sout << "F9LI3ExjgsokVCsnuAc25hTRWP6bUkWsd3fvbVK/Qrg8sYEpq+3836NJyb2BcFVBqmDJaW+MZ2+P";
+ sout << "dJwzMjQMFfRNnsEBRwHuVTDwa4tyR+1yFOqG514ohI4UKamdebXPlrjm278ztqaN/4ASFsVoQb7O";
+ sout << "nPvqiMT9REV9ZLiK8z2NK4dDr4KUCr/UihBZqX7qQWnFRyy0VooOFAyP9CjfohLthZ8Y0HWFDMpx";
+ sout << "0imNkxXlh3CIDNTRXAmgFupIEQyY08sZX/Oqx4NdzpxWLh2S0VJmIupzuxWTnKBRJXWZEVPKqsak";
+ sout << "zBsNzdtcqrF5dIIY/7d+8LFdEBIZ56wftYkRRvJt9S7mPIY++gohDronAX/ohfwXwu4jCm0OLWzO";
+ sout << "l4FIAdeN0m65Nng2pWnF6M+qB+b5BT3I5cAh7GF4t3woiWOBF7LnjOYmHe7ZkzPzftxeZ820e+eJ";
+ sout << "i1pFSQl3/H+aneIsjEQVGxgynGtvGW3pz/0f5rWrRdUG9ZYPJItWXCjJz2k/Eb3fHDA9JVIT9FEM";
+ sout << "XCsN2FQguDWy7cDxNMKxVRuhomjmVCR50/W9/Wsjg6+tnNNhY5Iukh40jU9uN/WShMpzXNv2QKxR";
+ sout << "bfUtL0zpojBbZOkAd1LZ++bQREzjPBFQ6G18eQa7DphNarttvCzw9qdgvmwpl3CfvW4PeFChxQ2V";
+ sout << "SmfUcuFnESjEN30zsEyFtIJNVd1E+4C6vDxk+FRWl+jGbzNkQ1GK+9z6M0HgUxBXMXcHiJbMEJ3s";
+ sout << "Ri6PqeKjZUAJzORigJmgOO5wURFI+3EVQ0NuPWfaQ/6UZ1n7fdXi8ncmO4jVwY1ptN/4tJL+bAm0";
+ sout << "eu/c6ug2bfNCTx6TnutxBAg5AvxlDrJIUsx+TsM50J4OZmv7pI4dC0UWU3TpzaYHa/cQ+OY61UT/";
+ sout << "j1/QPSquxIlWA46SGt/xrUg9iPIWw+2hdRBkhTBE6PrMMHLl5jxWpJ96YH5WDnifNnnhzRDcLfyf";
+ sout << "9nZYWQaBzm3JangobvnsDPgjF91OfeFJhVPyUwS5u+Sxw+NKPj9wVAaW3gZVS2BOODAud/EvFfQF";
+ sout << "08t3Ab27GGwWNx9ExN/jlq8EHAM+VRcyfn3hBVjLZdt9fs6zZliYdfyNaA/fgO1iLwY4DOSKgALr";
+ sout << "Vs5+KDTmyNf5DkAg/W/d1tA/o76/qXUz3gHdm8Q1TqA3ZuR3g1BE6oS4T9Sg62oYIthP99doW8ll";
+ sout << "FPr0aF+JHwXzG0k6Ao4wGdKmqi+n91pVYI7r2zE1kKtk7GyF0fSmcVnnP42TQfaUbaKB1bMT+a1V";
+ sout << "NMIydv7QD5F2af3El9np7/1S69sGpoNK7PLow71jdlCewGVrq+iYxZaVhe3xHwerQQ1uGfmRxUSK";
+ sout << "exonRQPz0yD5fkjRCqq+Hbys1CXe4iKa2uO0pW+yMlvRnMWpV3Bx6uxYR6pECBJ0x8DQHk4cBwa9";
+ sout << "J/vAlf6dDaVh4PIZy6PF783iAPRusNy0TcCxXTJbIg5YqUb5QAyJ2HEPbIaKeZwSnhytAJKP98JL";
+ sout << "JC+81f3cN/tJKfWQAJz4RgcrbhUfyf5yWK9rPOwvFf5WKfecfPWc6wpT4IqSrlDe3LQqxpFxJwfG";
+ sout << "dzNo23TgOFK+H176FNuW7jXD1sUsh9MA3Yycm3BWZ85cK55DOI3T49K2WB0KnFLkhA9wPJNb20qt";
+ sout << "m1M8QtKwF6jzpMnbBff/vM4oNL0K0QzXovI4gJTDUkHWUlZ3XxMk9PQIqoKZDp9v2JTNW6cs1zcV";
+ sout << "Jcm2XE2ZhTCFmOQ/DIG1AQIzQfOY6s/VRvHPSkIJH76fo1ex2jj5CmbGw2JFNLPDQIIHEjQJGHFw";
+ sout << "KpVGso6XF6CdMtcmlswoRrIvN0odvC0md0D1lf09ZuoyNt68aMSxgeBhoQYW4qC6E86Hef3TmzWO";
+ sout << "esZCvDs2I3UVKgPEkICz2TEHy7dcC1VzU2k/F/cm3+y33lloDem4Dh2igflppvhthcYCLOmFiEW4";
+ sout << "YtxiVJKpIAKbNHqv9qpxNdcbLCsxkENYKwmmG8E3fLSyE7St/z3dvuTuDI35lxANzv1N04YrvfEr";
+ sout << "dIPmvepllDz4Ua9TyYQoZezD6UsivW0gfWdbG9dbYnwAZRKEgQjRD1zvGUt/nGCUKdtBDh/Qu7jD";
+ sout << "c8KMBJx0meoY4jLZBSw3Rccd/KOvzC3UTSsBeTBSkQL7wuSMWZf2cTI3BiWaVTaUXREVmUG0eeSy";
+ sout << "W+Vym1qM2tPWkUm7V3toeS94LU44OlGDPyoHHUOsT663Zew0ao3+rSqS+KASC4L+6oqP3ffSI2WC";
+ sout << "517CtYtPA09gFqdWnN02mJ/+gEWrYUZXJsNh31AGQ4e4N2L1Tupy+L+mgkjTyHeiV6dUsvVQ2J36";
+ sout << "R2VL8EOQcchBMinBo0WKkP6xoTPcCwwMI7T5sHHR+KVUs2DJXTNluNFhYyOic2ImOwhoOHKwfr7I";
+ sout << "bJERGZYKwwBqGPO0mMnB81MZFumFzoo0SNhvNC9a74X8U6gKtDsQCeIHNXWsWxaO2LmjhlZqXEMC";
+ sout << "nrLi4UnXweqUgDscbWdq6fE6Ad/ZimmUJlj5iF6aXWj51B2VIgtYXxBFlVPURZDw9z9KPdyidzM1";
+ sout << "PSitwb6KwWZK8fJ4ZUVOUt1bIki9wAnpyDdAhrPtDVtngS8RJrcCVRrjQ91Vhr95kSTG4b6VtN23";
+ sout << "m3lhkU/T8RAVAphAait/TICzXeXdnFjALDIubsx1e3FMhV/TJHflVQhnahwTaUuIVqb1ZkmP9aMw";
+ sout << "0K1G37NbwIRzyHGVWnvJXxKfLeV3n0OJZ3W5dDmTOZSE1s7JdJ4rdEXpiMVsW07TB6JEtIz0c/AV";
+ sout << "IvDmgF9QH5Ly4Ko171Lg/tVMjBIhCiBU4zQco6brJHx+MoxEsNUXgUCNoMqqjd1a3F5wGsvhlWpn";
+ sout << "iwNpTje2A/ccVQmoJpDSNByMTB/0GsGJTjZ0dWR0KiltaQaKTlRFlGn/2jgbk+i7ujAGj/Gls6DY";
+ sout << "WoR/asND5U/rlyzwJS77EefK16ew8w3Nfy2g/vVvpIUQBG67CnjUzxpnutsI7KvZak2Yehg2NIZQ";
+ sout << "IAuyXMd5zixobwku63RvLT6Fd6D63HnQhEtgtPTcLJT6rQOf2cXAXN3RLOghcpM44flJ0PW679AQ";
+ sout << "pgVrmELVQr2Dvv2fCb3W5k/JdgvTKrJ2YPIY9Y7q5aSZ28VC1u1k6y/KsppJ+6t+TW8PloS+qKNb";
+ sout << "2tawgDRraMsNVUTMhABYEPZ+qoYspJPV4rKfVnELc8otpvkR404ulUsELxml0TndtntTjy/f9lmi";
+ sout << "I7pfDqPsOUfwUtdhuW1XyIhX3RFmavc/VFLHu8gVSmJgdgxjraoe1ldt4F8vgQu22uZu5yBLtxpw";
+ sout << "WgKVifBtJx/lZ4iAPMNJUZt+Fo+1K3uofYmOg78dsM3BSeghNcNI5ki4NrUJ3yWTzfvrUIr90Ee3";
+ sout << "VUaGz0/wtOsFI74ef6BaTCYNAt7psf/dwoow4r4FzHgXNqr9MtWvfp22gGCaRLuUWTHgRzIkCflH";
+ sout << "YyNFYHD+yTaKmSrYay2bBYFGRFe6Vx9b8FR7fmdyqq4HzRwQ2/FVeSQ50OHeT3vWTTg07M31JkZY";
+ sout << "VlTjnw8Ew9N+o+qI9AFaftksVdXr2YjXMpJMwbHcqK6himQLSkzkUEQXsBI6vQSPobBtPM2oNlCs";
+ sout << "oEf4AvHYmHxyyzVdSRjQqEoekWURI6htJxRQh0DaDhqOaRQmUp0AkB5StSD8z6o6Wyf0yvzT8OJo";
+ sout << "NEjaoZbz82eivQUGf3RmYLZIx4xjZ32GA2fUN50RfgyF/KzW1GNLLykJ2NK+saJKGZB7RC2ZlsI6";
+ sout << "CmkHIZeNwG131Opp+ygasp0GBJUzlKnEzmV9CIBigCv2oPPxewEr7T8/OGDPXWhY2LEgVbgyxLdD";
+ sout << "MnZlJC28aanAWGoGMcuXgyacFhOWc7I7TTml8jlQv1oDRJU39PQwZZ93HwhhZ2s87wuRYCQdXSH+";
+ sout << "pdtb9YblyosciNtYJguXl+2iBdGGIqNAp6oxYj/rI5l0pPY7EUkGEnOzQq/U3zCDPL1tdUymaOh8";
+ sout << "+XGYMMo5L34oxvi79Rh4snSaOO5h0fl0aaZES/v/x5QTtQu4H7qwVfWIsOg8ujFFDFeZmmJpb7pc";
+ sout << "ff03fNUsHBfS3yf1JvrXhVGDh7byfy8DTFCy07gXUaKJzQJNOjEqX+iu25I+RNxXbfHsRxsWdNEw";
+ sout << "6aHRUUb+zThVJGkglO5W/S32SJznnjkHdFu1WXBU/DbM7b/quJTUgWnZRLy6CugMu4I/hp5ArKCh";
+ sout << "vekyQySI/9TjOEPEFW37few/H060cZcz1V3DilvOTBrCoItzdjxZB/cmGxPln3mhkPqGr+NsXRdJ";
+ sout << "tPMRc91NxvDP1oBnXXEYD418bmxfvqbXZm4Q+bMq07TT5rWABCZ+NFmkgkXryGhfKQWqidxbRenT";
+ sout << "8teao4iAbwSHWB/Za5+OPYUS4b2u7OULXqkmbQDnTeJX6ou0VFYUpkXStbtLITLJrvAG0BrMq7G9";
+ sout << "09vbgw6e+krF5JHaFXKAgVf3/SlvRrZi6zgPT7wsY1WLGlMAFNAC58UhizDbVV5Xivj/mVxi29s2";
+ sout << "tZHKQRshEnuw1KvEp61O4HEnO2dw27v1000YgRz9HtQp9Ra0SsePIjlh8/h5O2VTqJgMlqgAiy9g";
+ sout << "l7nvX3Ft3a/K7S8GlVMwM8z4DiSzNf0irgnC/+sVu3ZAy13UiviJTv0gZ6iVL78GdPSqhKq6x8IU";
+ sout << "JGX2sbzthVZUpYPm65WjEBKUKsHWIdeAokKh+sS2TGEAo9COawULVwzYttKSY30UlsBLL/ofpjF/";
+ sout << "eCWfzunbpZ3MmkXJYVygXCsGgEuxDmWrhcxIF5/pPZDafmaxqHCml/zxew2twDN9lEJV/jqZrwSL";
+ sout << "I2awqrzxIp/4TfqYj4C8HOQGb4N246snRl3iH2tvzQZrCg1I2mp1s0+xiHESKtfecHfMt8hbb2QZ";
+ sout << "50c/3MAKQb9WatUDqfZuTnnwXMo5vm0Sh9KqLYQj81LFOzKzf1NDil38GSmFGWPsNm7vm8Q6S6BI";
+ sout << "MZafbg2gM+ohtKS/u/36ZADS9/bxf90Fzkn5UEjZUOIRBhYowQNilZzHCABNNXFO/5SUzSJqgLIA";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ };
+
+ face_tester a;
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/fft.cpp b/ml/dlib/dlib/test/fft.cpp
new file mode 100644
index 000000000..9d491e8fb
--- /dev/null
+++ b/ml/dlib/dlib/test/fft.cpp
@@ -0,0 +1,553 @@
+// Copyright (C) 2013 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/matrix.h>
+#include <dlib/rand.h>
+#include <dlib/compress_stream.h>
+#include <dlib/base64.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.fft");
+
+// ----------------------------------------------------------------------------------------
+
+ matrix<complex<double> > rand_complex(long nr, long nc)
+ {
+ static dlib::rand rnd;
+ matrix<complex<double> > m(nr,nc);
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = complex<double>(rnd.get_random_gaussian()*10, rnd.get_random_gaussian()*10);
+ }
+ }
+ return m;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ const std::string get_decoded_string();
+ void test_against_saved_good_ffts()
+ {
+ print_spinner();
+ istringstream sin(get_decoded_string());
+ matrix<complex<double> > m1, m2;
+ matrix<complex<float> > fm1, fm2;
+ while (sin.peek() != EOF)
+ {
+ deserialize(m1,sin);
+ deserialize(m2,sin);
+
+ fm1 = matrix_cast<complex<float> >(m1);
+ fm2 = matrix_cast<complex<float> >(m2);
+
+ DLIB_TEST(max(norm(fft(m1)-m2)) < 1e-16);
+ DLIB_TEST(max(norm(m1-ifft(m2))) < 1e-16);
+
+ DLIB_TEST(max(norm(fft(fm1)-fm2)) < 1e-7);
+ DLIB_TEST(max(norm(fm1-ifft(fm2))) < 1e-7);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_random_ffts()
+ {
+ for (int iter = 0; iter < 10; ++iter)
+ {
+ print_spinner();
+ for (int nr = 1; nr <= 128; nr*=2)
+ {
+ for (int nc = 1; nc <= 128; nc *= 2)
+ {
+ const matrix<complex<double> > m1 = rand_complex(nr,nc);
+ const matrix<complex<float> > fm1 = matrix_cast<complex<float> >(rand_complex(nr,nc));
+
+ DLIB_TEST(max(norm(ifft(fft(m1))-m1)) < 1e-16);
+ DLIB_TEST(max(norm(ifft(fft(fm1))-fm1)) < 1e-7);
+
+ matrix<complex<double> > temp = m1;
+ matrix<complex<float> > ftemp = fm1;
+ fft_inplace(temp);
+ fft_inplace(ftemp);
+ DLIB_TEST(max(norm(temp-fft(m1))) < 1e-16);
+ DLIB_TEST(max(norm(ftemp-fft(fm1))) < 1e-7);
+ ifft_inplace(temp);
+ ifft_inplace(ftemp);
+ DLIB_TEST(max(norm(temp/temp.size()-m1)) < 1e-16);
+ DLIB_TEST(max(norm(ftemp/ftemp.size()-fm1)) < 1e-7);
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <long nr, long nc>
+ void test_real_compile_time_sized_ffts()
+ {
+ print_spinner();
+ const matrix<complex<double>,nr,nc> m1 = complex_matrix(real(rand_complex(nr,nc)));
+ const matrix<complex<float>,nr,nc> fm1 = matrix_cast<complex<float> >(complex_matrix(real(rand_complex(nr,nc))));
+
+ DLIB_TEST(max(norm(ifft(fft(complex_matrix(real(m1))))-m1)) < 1e-16);
+ DLIB_TEST(max(norm(ifft(fft(complex_matrix(real(fm1))))-fm1)) < 1e-7);
+
+ matrix<complex<double>,nr,nc> temp = m1;
+ matrix<complex<float>,nr,nc> ftemp = fm1;
+ fft_inplace(temp);
+ fft_inplace(ftemp);
+ DLIB_TEST(max(norm(temp-fft(m1))) < 1e-16);
+ DLIB_TEST(max(norm(ftemp-fft(fm1))) < 1e-7);
+ ifft_inplace(temp);
+ ifft_inplace(ftemp);
+ DLIB_TEST(max(norm(temp/temp.size()-m1)) < 1e-16);
+ DLIB_TEST(max(norm(ftemp/ftemp.size()-fm1)) < 1e-7);
+ }
+
+ void test_random_real_ffts()
+ {
+ for (int iter = 0; iter < 10; ++iter)
+ {
+ print_spinner();
+ for (int nr = 1; nr <= 128; nr*=2)
+ {
+ for (int nc = 1; nc <= 128; nc *= 2)
+ {
+ const matrix<complex<double> > m1 = complex_matrix(real(rand_complex(nr,nc)));
+ const matrix<complex<float> > fm1 = matrix_cast<complex<float> >(complex_matrix(real(rand_complex(nr,nc))));
+
+ DLIB_TEST(max(norm(ifft(fft(complex_matrix(real(m1))))-m1)) < 1e-16);
+ DLIB_TEST(max(norm(ifft(fft(complex_matrix(real(fm1))))-fm1)) < 1e-7);
+
+ matrix<complex<double> > temp = m1;
+ matrix<complex<float> > ftemp = fm1;
+ fft_inplace(temp);
+ fft_inplace(ftemp);
+ DLIB_TEST(max(norm(temp-fft(m1))) < 1e-16);
+ DLIB_TEST(max(norm(ftemp-fft(fm1))) < 1e-7);
+ ifft_inplace(temp);
+ ifft_inplace(ftemp);
+ DLIB_TEST(max(norm(temp/temp.size()-m1)) < 1e-16);
+ DLIB_TEST(max(norm(ftemp/ftemp.size()-fm1)) < 1e-7);
+ }
+ }
+ }
+
+ test_real_compile_time_sized_ffts<16,16>();
+ test_real_compile_time_sized_ffts<16,1>();
+ test_real_compile_time_sized_ffts<1,16>();
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_fft : public tester
+ {
+ public:
+ test_fft (
+ ) :
+ tester ("test_fft",
+ "Runs tests on the fft routines.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_against_saved_good_ffts();
+ test_random_ffts();
+ test_random_real_ffts();
+ }
+ } a;
+
+// ----------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'fft_test_data.dat'
+ const std::string get_decoded_string()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'fft_test_data.dat' we want to decode and return.
+ sout << "gO1l2wKz8OsyeYMPYcGx6QdBG65vnrB+omgAJ7Bnsuk9vkTw/Y9Y/UZEFXhVf6qnq92QHPLV16Fo";
+ sout << "a+IUHNTjoPAfBOTyfb8QRcTj9SaWpxA65+UCJ+5L6x/TEyPKDtB23S0KRpRSdfxBSW9/rnUrkIv7";
+ sout << "6i6LWcxKzdsw2WGsRCX1k3t0adQW49m/yb8LV9Loqs7/phzY7HkJ4D2PLtpc6Wyk1qG/h6KQ7nkF";
+ sout << "GFkHIoh+xKXhHpqWaSofx8H8m/++H++g0VSPqfQ1ktFz+K8UtiGoyR2GqpP+br47YLXG3WqVU5Km";
+ sout << "Di3+IjQoBH2m4jykD926aRvdRrgUH4gZunokl+U6shv20Zm0NL8j4A46/2f++YPGCVBNJJmcJdI7";
+ sout << "9RlPL9SFbJ8rnH5bbLvZ2pKZmmbeZN78yzLUhdGwn4DGpf/Zo1fU2YPUjVKkwY6olW4w3tiBl05a";
+ sout << "cS1HwBeQjnajqsXNyudbrBkM1Z9XiwM+J5iMsu5ldaJ8iLn30W2Te2RnZhJRHO8MgL7Fn1j0n0Qb";
+ sout << "8dB+6aQYv0l/5LQkr5SX6YSRYX5b5rnqhi8IzJKms6dzoyBm97IGTm8pRxtLXcmsk1MvJcHF2gl2";
+ sout << "CslQazsl5iIS6fMxEodmlMdwdfIpp/6MqmeIydSHwdyJJZnNPl2p5X+Il5egmwdaSoDQNphPfTaQ";
+ sout << "R0Xh3xqsZKgHLKxB14Rsf/R7Eu9ZASTByX3UrEHsSzLSUo9/G+tS3n1iC30Liusksh2Wkt+/QtDy";
+ sout << "A1ZX31H5OlSFwCYC/TYitwyl4U9k7WhHBDoT7MdmVTYQEK1dK48nwOhnZa9prE8n3dD40CCe25q3";
+ sout << "Qo4VVYc5tBWu1TfTbshvkmHAcp3Gyw/caqq6jdq5Z2BD1b67i/bY66xhmowOFS8xeA7v6tKdkvpp";
+ sout << "Rk8FegzVdB72wpw3872T4K+eplMDcCPGkwIieF5pZStWxhGsNOC0p2wvpFvTpQgfNOGUvRt69hsd";
+ sout << "xaUEYlWZcY3sfsiOwPGgBUEEv6b+8W7+8Ddj8Nx4wG+bdWozphfz7THbmOeaDM63imIEHmJbZ47I";
+ sout << "QgoyzFD5WoWtZ1wMEv4LL+a63B3FzBcvPvdPaa2QEmyiK9yN7GEePs2Fv2A3ymhGw5NeR1dOzAjz";
+ sout << "lEQW01p8opk/dpyLO18zj8d+Hn4EnJkKD0p1u+XuLRda8AnRu/WmSOOpyG5EUrUoEyuvbECLbY9X";
+ sout << "3AMgzkbxltmZlkyOOwfCGM0yumGYKdz0aGKdyid7ddLMTpQ908dCNLyRgTybdZG9137PQirgX5+O";
+ sout << "08T/+L4EIyyrslOYxpUaLm2ASnSUgiivoIJvfnu8IeH2W9fPupY89ioXIYuwZU8f9FDCA9z7peQw";
+ sout << "9H6l4PDdDrB7nwQhncpV9FYLkHQLbSgE1VD+eL6Y2k48pI2zUndcoHEZW72NcmK6E8fDvfgbKkYD";
+ sout << "m02RiGuj4tvEEsIVuVa29Q0JGO+37n7Mlz7+RMcUMo1pLnh+jibas6R+1LCy7b4ubiKMFB1gvjut";
+ sout << "gjMABy1dJxSOdb9xUa0K/Alwwu3MxdkrbTxwqkn0C2JnVV7z9S2I+PWcfZKzcpg8Itzh/ON6I/DE";
+ sout << "EGK3s39XhLI2xPg3PE9R9QMaisqxb3FeP1NkBXrLQtuQfrSk+KZk6ArQWVgtem799fxgipQsa5RH";
+ sout << "z2Dq9t+pJzNGUnWg5PWzaAY3lWMscn+BIRhsZfDJ3QBtS9Vmib8r2dtYwXi/Q+FhnAHFfcXbhDC3";
+ sout << "GHn16aP2PY1sw8KMtfPRAcqY8Ylbr9EQXjWoIYUs0YyX2Ks8ZgibunTPFz/Wu98RVYswMtjubFaJ";
+ sout << "jb0pK9S6qoe/w10CAAHqoAfca7uMOxw9trZZmjCf5vF4leH/nDgsNjesYn21rE6rLhSbg8vaZXo5";
+ sout << "I/e1uhZlRz4ZNnMlZSnL70Jt0IjuR0YNphCsGZjmvvZ4ihxrcLrHvAcSTJuqW5EARtvjyQWqBKSP";
+ sout << "5XhlkrI73Ejvy+Lhv6n6O7+VrfWa/tGRuvvAToS1wPOP1T2oniDXsNlD0QbMnCao+dTWgkTDiNTk";
+ sout << "sFxsoN8YjwHqYUAp+hfnu1Vh2ovyemAUmo87vuG7at6f8MgFSuZffmBkGuijKNDDy7OrHoh7+5/+";
+ sout << "aOkcvp0pW3ONZ4l6peRNvzaW5DEBTvcZGvRwVCHWII1eGpzeJKaHWvDfLqjaPkFrG5pR7SGCY/9L";
+ sout << "73W2U0JCe2h7VjWbCM7hdvJEgYi/mEarVQpt+0P834es6Rm9rsMCbgbrWl7uv35+LVMTHU29Oxln";
+ sout << "bDzBUJQs5KIA81IWR3R7D+HuJvpMkAYMF73c1owI7K74SBOsTq1ayC81aNlK7YwOOjZyBqwsQ5sy";
+ sout << "zZi0k9AcKRGmTC323o7Tp/n/gkAU3NObTnqPEJitjGloXqrhPvorixBhHXSZy+wgL5R+04KiF1uU";
+ sout << "LEFOzJ0zKUMstTB+fgC7D6ZnVEtUq3HEYnmaRRwEhRSgMTLXE8VvnOdo802pMVN5GMCkH299rJm5";
+ sout << "Ina8mTwlC9JrNuYHot5KK/Gny4KPyUeS51cifByPwroemwBHe9EmKCkcEJPoDpG3QMaV36aopyJl";
+ sout << "GwhZxaZSqbut9XSWr0IMxHUkFeslRB+n/7Vx+xWpDNjQ7JA5S/B0ZW+YBQPcjA3sRQTey25JD4Jy";
+ sout << "RsULxNY5e3mjn59fI8OpBOYfNPTt2Jzppm1GDpym0LHuz7KZ6xk6QAyogk+HMjC/5RcQA7zJWDRM";
+ sout << "dXC4CXUjrBxVzmm/YHXv76LrsaFdzJgn+/qzlM6IvIgicMhcJl+hA1swTkgcw6JRalJiDqnvapKP";
+ sout << "V+T+/X5PSNMswgZURHQJ2l0PkMrUT909pBOC9t4GCsK8k4rYS2o0I0UYfcpm4jMRU5X34zlT8Qv+";
+ sout << "GV3mA0oGq1U2dJwArlPX3gI5sZ2Jsw7Qa5edvQNG5GoRb2j2Muo4AkZXXjbx0KEa5leLIhVL4BAE";
+ sout << "2GTdbL7T8hUGY3QlRQGwSVAytjUfXg4jCyn9w6ZbxUOu5MDBuCEtrhRSJNKuBLInK3Bh+fr2FshC";
+ sout << "T1eDtIFE2EDEaSbLj4NCNWpTFdKMXZ9CQg2VtoVOIJfgKzqAjjcWX8kqWpMFlQgtdTfIqN7gnFit";
+ sout << "do/FO0OzLghevyexHdl+Ze+MjITKOF0mTPPMkcIYcINIR1za6q3rLDZg03+GouzYhL8lwM3WAnkg";
+ sout << "Qg+NM6reQATKFK3ieOxacZYnIwOR/ZMM/lO/rHY/ZbdAnJHbMBWwRtK1vDi+o+ZgS7EgsDpsmz/l";
+ sout << "PguXPK0Ws51OUhIJJ5YDBv+nVPJabxOYV3dU0z49xFpxNTW9pTISo8mKZvLp2D765kExGJ9YKoAx";
+ sout << "Hfi6WEg3pFS9YQLNhOZjE4bQThugIWXhi+2OPgqUIUoV5ctSnP5Lv+xhbkZfjnQQQQffrrU4peSz";
+ sout << "6CuNEVLuNuG/mc3WEDZwf1HxYv3u9pr7A79QG0EROf23zPzaf5biE9e9xH+ruPApRHM58H2RpxXU";
+ sout << "RlkYnfoAUqyvT3Lhhk6ngv8Axhi4otvz7sRiXQmZO7mtzWzsCTkCJoziwRKlD6P6LYnbm4fRYP1M";
+ sout << "MvOuW3NhsQNrsDtgMuvqiVQpRzg157ES1i1qnTjJxTD5emK1RljuQEetbGksyetctWdWiEd8ZfSh";
+ sout << "DHBJC2FLucmkMt0LHsVPnk4ni055uMRdKPRKjTE2MjpEsxR52xiWR3MtwXiEhH9fZnUl1IdBl3PG";
+ sout << "TfLiZ286m4ePm6JOgNM1chtZir+q8pr4ghk/xycWvHmgkqT9dQcFP8iEtlVLCS22/2mS79cTev2r";
+ sout << "yE90otp9vibcTnpORzrnLrMhhpmYRTxRjRaHGhwdJYluARJFBBVTMEenK2ubdLOJ8skZjLzPv1dt";
+ sout << "9IrO1sNUwrMpEie8PG7D7DzQ7//jdlC/HUZaGKrwj5aMUULi+ZYiBLYoeL4N8ozAK1u3KtXLKlRE";
+ sout << "3Akys4Py8+CmrY5qaaDOXZvwl3FF3skmGhx5KValRXrbndqr3Cks0hXglHgNonZh795galZwu0Jp";
+ sout << "ww/mTQLCV0djTdEfjXBUnP49zyGXWWsEsl2jfqEAfBDcT4+mMzAUtBSwwPJYXXAJQz45R32MThNb";
+ sout << "k21X+rw63QJe0zIbOJepHz3jaedMkj8GKNYBjqzibNqfYelunBUqW0bpi81HYdN5OFY/3GNKgygG";
+ sout << "4R5HJaP+x9e1HxehpI/4pKFC+TAIb29uSV5GtkNTb1fYLm0kjeCZNA5GKtf42gBY52N6STl+lcI0";
+ sout << "gD+jJ/ogknne3sRtEJEtCFFe1c50oikyJamQbeUO1PcDUBt8Phl1rI/p4PTP+H686usJVhSDY+b5";
+ sout << "9CdS6F7XSSDiXlpFl+Esex30fRZ8zAQsTo9oN0sSZUUJKcyVk0dCqw2mHWPpyM6hYKQ3ij1nYjYl";
+ sout << "3PzRfFMlu+dgStcBn70jvlEv5pOWXb2OqrN9nJtb29n8jrB2K2nlbcYoPPiQ3yXk+Wpom82LoT5W";
+ sout << "F9NeNwwAB4EDWtB96OU6noW8NHJj7NiADQJGvQpk/3JzIzeBJQCxULYJMRJdBKf61+24F791reHa";
+ sout << "qrH+rLUrrv05dIPDTUvGW5LQLTTFFa59OmMIu7WJE7Ln6gMIwDw3FXnGFzaWnHlHL/9jJ0zM1FQL";
+ sout << "kfK4wTd++GbeI0gsnXWFK0N0kV/FiHm++J4udWwIXZxH7qZCHtwlT/5oGDVujtAtOPag+txUrjVc";
+ sout << "G4iLeiPbV/2Vfc2D1oV5/yyXDDii9qrLH6SOOfgvdiJZr7X3uMUIDGO75x5wBDSxr9t3I2CrX2dM";
+ sout << "M6kD7U1+bf5QVRbkh3Us4NAhFVnLNEcrm0x9Yx0wRmxPKgJeGGbWi7/BHi8ShIFllizuxuMyfypC";
+ sout << "hhzSlxxbYAQwtcC3cHEnyYZAO7HC6hyke+HQJfxAmKyfguGtzEzsiG18XJVruwz7IoOpZS/O71zy";
+ sout << "Nv+T8trOhy59ZUAgIsCAAQJYEBWl/T/qFtkE+tITbVRKtHjbxHSeN12OnHFRoKguJYaakTo4qLs0";
+ sout << "fr4E4nZUMfjdF7oI7YutegY9TkiJ9ujLJw4pfY1XRtPrRukEl8orypWXq0gErnYO/RVtK3XImrDp";
+ sout << "LY5sXH5pNzkqVH9VCl6lh9sg2HWjNwv9bDcDlIhvTL19Mx9yUtx/iQtG/OKy22tW6ByahPNnMNtA";
+ sout << "tBVB38RLf6eJr68mhn10Qg68cXxVL7/zEIZd9rUaCo8xCzeFblDNErKfG02JJ6fbQ6M6ZdNez7Q0";
+ sout << "x2IYbz2DEk0wHmR7OtA/oTFMvJlyMt+dDWTEpHnvqkbe+veENpxn2WWy3UsumkvhhtzzmLxyD6Sh";
+ sout << "mMbMPwgUjvMG51JfRrgMfJzT49z0sebSfzvid/9QV4lNkR7s9nfUJEwAued4S4klRy3LiFdQhjQR";
+ sout << "FOZZNqUge8vxVOzVCfS+xsjvnGrd7azt7LJg6wPXFgPfeE2bRlx+8AoRFG7SUpudmm/bkNw+uNgS";
+ sout << "YRdaH8p16RyNoMlSfi/7BNDhtKwrl202pVuCqhFey0mPYehYee2HhLZs6ph+HKMYy8lZ/ac1Q17d";
+ sout << "1tcI4WH0Hz0B/3GWl8xWfoq2OO40EIjuCPNhk70MpiytWXggJrKoKPu52GOqTU8+jZ6F+u6U2muZ";
+ sout << "6QZLYXDwPaNz/lq5U4ACw767DkhUHd1/h0g6r/RwtLKxdrzYldQto99TAMmHc+z9aIciTv7kl/Gs";
+ sout << "WA58nI8aODhwjIkOGaExdlR1k/3JR2tAAj5vRzYlJeakhAA82pA+8xMPZr3HRKMPCcCJZiOFUYkA";
+ sout << "AAAIGp0hTQAAAAEAAAABAAO4M25wAAAAAQAAAAEAAAABAAAD22vyAAADGD3aK6jS5oPrMPzwAAjt";
+ sout << "xbxcPWpGahG+GZHRkwABJjSNeG3dJthsOADhIXZ+4e8jAWWTyn1FQrzNkDMdvhTq6iuNBtgaodaU";
+ sout << "LlEAl217cnKFEVX0Gz4mAAAAAQAQ+2CiQuAAAJqBbzxJicET21QADU29xADCbz6wuq0KAV9tgJYC";
+ sout << "z4z1fuKC2IFuACLkvCvxAAAAaRl6AAKB7r5zjcz2HSjBdaDc1QgdOUAzmTdpgegYYD9XVQtaphsW";
+ sout << "sUhXeeIliGybsdhruMlJ8hi2YzzBBZc1GwjNawB2sz18UCIbQKBoDMBo39MbAAAAP1M+WcfB4DGK";
+ sout << "yDXgydAAAACCIiA890S+Coil7foud6zPIspdcqIDxhws3Kiht10f5NDHUhjgTYsAjtAgSoGLQ64J";
+ sout << "iNm0zrLDZkuHC4Hm69wkOD43AHbIxu+k5r5vgCW/m4traQAAbol6XlYIroFESJxqPkH6Zdxu3wnY";
+ sout << "DA1HzRnsBIlQ6SvPrboLtfVXncBN7aM7vLaX177RTxKn2qep5WX3/yG9sAP1QSkqapaSdLpB0Q2N";
+ sout << "9t4O8ryKiLFvPQrbFhK3Pux8X2PWKHAzZfkmUSQh+OiOICNKDbPRY0Es2GaX3Qnl2oIVflDINm0i";
+ sout << "Y6t8x0AZriURrafLgtzuoqaC7rAYwb1iQoFJPwXiZJNIk6W8g0623IGSygd7aZ+xqv5NjU+q0C9d";
+ sout << "0PJs8kZ7Db15tjjTBIoS9gBNefJg2D5TCJjEPSzPcZeTjPzeZJeK7v1KHgunnfi6igrT1efQvxDa";
+ sout << "KlbIBaR5Mk6fxdih+YOFTnVsT1mE8b8nffJ566Rgc6azYkJizsRen8b2g7jzgv2O0BOI7VtdrVpV";
+ sout << "BxoQ58p3EGMCV/mlDhcfVTctvr8hrjUu4OhN7UUoqi94JRXL5XbNDcCbFwXScln/Lm0bkzNsDnlM";
+ sout << "R4OqLiz3ktIpJhAtUemrNZtPa0+/Ge6PILu4jPNom92BcmxjJusoTOrHSTQg6cYtcSB8spjVRdpj";
+ sout << "tFfYfDY/6rxKpE5X+LU8P59b1/cdrNSbqkuRIuGFFzkQDv1BUNfa50aIKo53OmvDWkeEpkpS2xD+";
+ sout << "hz3uN05FteKkZ7kHDPmEEJ2lUHB4oicxgkseb8nWToePhOkr2JcNakTx6yc+ZT7bzPcoT0hueCpg";
+ sout << "Ljzb2AQ0UdAJEAD9eruD1rF9PDEaXD/W4D3ja2EgvEY9wSMR56Ne8LSi0jeFjp8jKxcbmBo848xY";
+ sout << "dofjq919a3V9KDRUZ3d9t2Bmfc4yFoS6nBZCVy9klxK2ZaKePGjeCbENr08cfenUT7kA+ZQURi4u";
+ sout << "WEwCgdui67K4H5NPvbq+QAoKn9d+ZHx2YfullZgBCi34oLzT23yccD4uxP4GbZVXakvv9lLoq+rf";
+ sout << "T2uxZr36V3aJlhqVoSReJ4Oqz5qbTKNH9F3S14GFJOTByKZP4XJwVytHIcuu9JLpQPDt/nkREX4Q";
+ sout << "0cKeNqXqdujkp9XCAZEJ1RkvHE+F4tiUCTKHvoCslgs4x9alnUWVps4Qy5CMaB8+x1eHM3gkuf0Y";
+ sout << "qNIFuIXUybNj0hnKO3IV5k8m2MURJiZsmM/dg0fkwJG0DIAmCFCXdugfHMHpqXZR7IBfA+Q6BICL";
+ sout << "Njxa4BWCRQoeKc9LD1Nits6rbVmqkKPAlwc+yhfYzny/3/ZHfkMuF/s6CBYugf3dYMIch10I/QRi";
+ sout << "9mVUWdCIacS1G42Yaja31j4s+304a/luTAsDKlOObmKTzDV2fDhbKSLToOY9iXxRK6KJY0GydspW";
+ sout << "ak8OvtNCCVvEsA5NccWOn8njo/sryvQgM9yzV8XCI2MDF0blRNFJQR72EDdG9NXKgg1gj/vG51dH";
+ sout << "CHj9E5ffneorEoPjn8pfOny29jcb16D9lVc1zcp7v83pLXuAyUp3lNC2ff/PcIbRMpNns1MnyV2J";
+ sout << "8gjsQTqTL9AAcvz04ohVo1LbZRl6rl2D0PHAOCOJQAJ65OA6BHxfeh7EDDnniKfLlI3CD6W5XZxW";
+ sout << "KPVAa4RGyCcSLbmb5d658vkB9rBKvaqncbiarQVbyLQ5cCRokVd9HTmqYX4Ky+0yPVcmoXAS2B7Z";
+ sout << "S0zXkeuA8Lo2ZYRad7/CBg6foq40dpQ9EPw19H0YquMXeGVEsgSvu7jBCYrtuJzL/wlxe+plrjXy";
+ sout << "E4iwHoZ78KKyOgwTSqKtynp20YkZG9NC59XWvyrd0oTBrGlFpOjer+OtcEgl+3XYl1q66yJTyQie";
+ sout << "x/Q7AjBZWPmlhEkktLtXYW1yIqr+EmYJqJJ4Bbssvsa1/jd/EmZQV9//HRBmber5Kw0C8royzI93";
+ sout << "uzM2t59sG8hnOHXCjAQgV/HuTCTD3hzeDgrv0aHMfIC+mx5Xkt7mLhrhLeODhJxguHb9a4pQwhfK";
+ sout << "gD0DKhyk0RwVZBNF2+3UfK6bJ1zeUgf0FJ6Dvak5i2+BUVtohn2qjbcIRFZKEtE8Oekca+FE+9+S";
+ sout << "mTsAIvR/cbfuDVG4cmQE8sPP2nB75KQJHylHW3ZvR5v1icnLfob/CfYMmfSPYDgDFx9cYroX/luf";
+ sout << "lLKKxxQ+1r4TIUGKcBV0ZJcvjCwzU3C2eG6oN9P99+qndIXYmvRvpLmq5QYyjsRHmXn2MTKSa8nl";
+ sout << "y+vPwWboutMugCUmEfTXhvc33o5/KKWU9cVSP5G3mrGBDu4BfG+GeqP2+DtbHTi9oOYm7723fFF8";
+ sout << "CUxOvoAQkOQQWC7Wfd1QGgsVPxhz7FTsviov+G164lh/4Qlkqy/8pzEJdQK9uYmCsvcip7tKbzS9";
+ sout << "lRX9OoPwQZQPWPosqZjbYBmEVr/e9jtFv+2pH8p+5S0GI4qiNg8n2fZE+isn9XamDpOqNEpKk1gd";
+ sout << "Xg/ombkOajBBxBlpNbXQa4aZylfiz3ANw01leRleTqeHB3HdNnTaJn3mr/lkKg3DYIA1N9/Iv8jQ";
+ sout << "1lQexZCF0jEDg51sUNPF2yDGnpSpZVkDLXCGIlKe4BI1/pR/kiqrEdg/ITP3+tVhND3x/pBWKlNs";
+ sout << "AteO6/IZrK4XOQ1DnZgJSAdz3Qe2uO4wY/7MQBhFO37V5gAQAQVLcXsik3FDcobieQdvvoJM2Z3b";
+ sout << "i+FGg1vcn01gNGDH0PvTKSEN/KFYTpyKDw3sjzgLbfEPOJcGmIFj4JUuaEYB2TfQfzOwzM7QCDQa";
+ sout << "6jbMHpN4VvRPQqZ879vRWzHhg8P2M3rJmcQsrjaJDIL7t41eMOmB3Ey4Vajya50NPPyVjXEtFdYj";
+ sout << "TPc49LO+npIw81WlxPbynhk9lmLeYwr8LALpc5dNFr8BkfCNc3C+IFi+RHSdq6tj7vXqvE+KtH+7";
+ sout << "lFZNdvI4hFiIrDJssynPUFAR7bob0zEq2RxDGJBSe7AmmwhUgGCHRFXlpJg8bFCFs4rCgVrBctry";
+ sout << "AY5TT1WWTTa5P/jPOCTfrUOwjxgGD6ubejoyGIoBPfsRM57XSYv9gQKTi5hk3k4qHQnItrf9p/AO";
+ sout << "LIxqMGF/nky2Z11JWz1krqtE9phBhmXnMk9ap1YWJd83L5Et4wxpud+J2JxJoM4kjtnG+HXqdEsC";
+ sout << "KCg7bNrSyAjtohz2vQvpXsZjWkq7QT+fTzI134PhMzbqnsWdKi/dDsZBNbXB4ua60uqFb/tLtb7n";
+ sout << "sNBfRnWfch0qZLuil5eAWkLlRC4zyaF1zJmchHnVync81bHIJVNj22+ctIbdN+P7aCYBA1n3sl1U";
+ sout << "0LDKWsXycnOxmKFUMm8kh+f/eP3BQu2Pe5W1tYDQnge9rvF1072VXvjpDBIna/VPuDwCFo2jPPl3";
+ sout << "jbxOuvZTOSTWOwyiX5B8aLBfRXm7wXAwRoRy4WLr2dsiGFGSwP+pZlJLfNGY1vmbILPg/9iNNMdW";
+ sout << "8MBRnhh4COlSw5/NxCl3FtRLfO3uLe3Z9+tBpX2qkUHcFyeulVFINjZaNB8gUBPr/Ub6/pk603yY";
+ sout << "YTEqMSo239BJZvCsJmpgZaCA/weLepsvaEzpJvjI3Gvo1Jf/zdm+eY8VVwprkj4WKWKWjHq4miAf";
+ sout << "y4TRxVYOG1lCH/cGcbepOcRMUG6uY0jTP7tqNfd4Re8IXTLCq1P4EOGuvkIe8hT/YdPP2B6W+Rd1";
+ sout << "z37NgjkKJqiSZBxpnj4WZLmdJ2eOUUJOR4Mce1mHEKN6gOhzzFRK98ZB0WEI6jITJ4wNcdDpw7Eh";
+ sout << "1Sg3JvoigX7Onq9eCnb+5uXFQbQrffuNiTCa++zx5Zm89m7ZuTJ5NFhssQ3v/mv8Wesl/9lebi05";
+ sout << "KOVcyMAq9Fzx5Wtj9GMHrTNTyzS33CGVrx3Imh88CXZ79PBLBO9V2Lpjk/yIuCyP9pKezOZDzTED";
+ sout << "rrMRA+AkfStHcPOL8WwGaAQgM+AlF6FVrKzs8TQW3hrBUztSeOFrxpDLod53zDcNaWRe/gpKtB/4";
+ sout << "RKRjjso+LANmNLW/IepM3Jy3sepn4slG9YS/up5puIZY6zrsw8n7nnejBrUBSgZNUaeYLCLhWcWC";
+ sout << "aa/M2BfeOT+X9PXJyzvQxDx/fw2duaVO0yRYb1ZNwtoOXWWXzBmoWKVrlXcegQ1wDzDkLW6lwnww";
+ sout << "4wJ2tMR5bWMUJii/0Ep50BMgAG2TrSK5jrBpiAaGJaSOB7k39YsZ/3/8rozN1IKa2mrK6VqkvY2Y";
+ sout << "AeOhdivfgdgccST6Ymbe81UvjsiVeCQx6tI2RcnR7NTxLC3guqwsSirHXDHTflWI8aP4bPb895Nq";
+ sout << "7JdomRqug/eiaoSfv4AotVU89pWyzC6FAN8UdnEXjZvYNA0gf4plXcMvlLKmRfHj/vs5x3v878/m";
+ sout << "elmdsnYX+sIHEc3hAZSISJoTZkGEptELFMW85Rj87/J7d7cC1q6vTMSNHgpysPX+2M9BNMEGDpJh";
+ sout << "baYrMV6ASpbVikZm97PCzHNnwQAxsOPIFoA/ZtoyXleszvtD2jgNsKiMQo92dIFDAJU+4FIDWG06";
+ sout << "7BoF0nZgUUrfwzC0kL6cN/ui9mBpnAu09t/9dValOs+/Prfp5NfdYesdUpJCqt+o3/VcgGCd5OfD";
+ sout << "1n0lyUjd0g69rM73kEb7jOFV6LhN/5sfmzql9DIqUYtaxs5nJ94eFkp+lSLeXKJqBIrxEql0JL8H";
+ sout << "ISH+HMQBpE/hWIkXJ/RryGxYv/SLm4mfKYNgp8i0KKzpp5fiK9ZlJVmyLAM0eRAMllUa4j7Q0zNl";
+ sout << "p1EO0iv3pD9Lhbb60VlD7ObwhDApO6DpIy0mjj1G31DWJi4uEzYrUttVsSpj6a2+rrI+7nMA1wDO";
+ sout << "OEGWM77EjjTElz2sU+1w9gTNn6j3uOFu5Y4+/ysXnAIVtg0zQluCSflOwSAFyUvpBNoKVnQD+mGH";
+ sout << "870jvWJ/y5uoyjwaxl33+t79t78PC8ycBjvu5M+RFchnLW3QqUSP4l84gYj5oLsz38LzvrRU+lUk";
+ sout << "mFDmrCoDe29pLZXYwnI7HHYPEtPBJX2fdBaudv244Z/a0NPgMSHS2uwdTkdSdWMK1lTBt1GB0+XE";
+ sout << "HqdlnBbMPq9U4y9Uhh1hxdBZHvAcrhYjXDSvbDHDzZRE7acCvLmAOR6aRoGup/WIowNtU/wXfK5c";
+ sout << "irNg4hSWLIjPNB54AkPsPc99IxGPH66PnE2sAWFALd7E3GnAo9N7t5WniKWWI3xtmQLbSOHwdI37";
+ sout << "iAOHsNgX5TjGzUYwwnQndubqfV0NY4/V86wO1Rar1qBsIUSylkids760J0HqyUsWNXxsS6T9Hq8y";
+ sout << "0szlFA/E8IBYgdH2LwkayEbDbKMsonJC+9NhEx8u3dj4ckmmKXOY8NT97XlqxomKyexbsKu9mb1G";
+ sout << "NtxTI3Yt2mDKyt4hzMvhF/DgvKErMfTMTJ/h21uaZXrmwu9G+yQQJVaB/LEfrAenakK5mhmIR0Ne";
+ sout << "+e9cQQSr+iD8oZMy/IkM5rd5FOk8FY9pZb91hXaWNIMDfwyfZZATaJruQfO5cgjMGXSjpq2gFHW2";
+ sout << "9m1zGxyWrEkm2lV6FQlPLHBGybLKxq0VNUqIsdM8VX9Kv+6i8UgN9Ee+hyd4a9In41m0Z50jqgja";
+ sout << "Jojh/Np7WSPqnPhNCv6/K0teVxq3bo3UfaXlrEZtkAi0hgy67XtZoBBQ2Se0ZWzOntgP3Yo3OI1S";
+ sout << "02Ta7r55Ox/WYR5NoFoT5P4ihVcZVmD8DtuFLtjWeWKrHAWPpDDe0RYpN9Ma/DOOlx+vf1Ir7kzz";
+ sout << "oXXOiVjM/hgKR9QjX1N05clcmkG8uSoxtaOU6Zov8BKIZAFfTMdQrhKBrW+Xgi5sKef2mBhPGwyx";
+ sout << "pnudRmwMFKk1D8UXtuoEHYQX03cvYEDmWberg887C1ca4UdAg7b5/mysr2g5Md+vGHrqRtJE5Zhx";
+ sout << "p2BFSzeFV83Zpe7PYf2uTLffLleJSKV5l6ohKDh4V2P4ztKvNwTKZYnYFdWlfMPUz3svuvihxG2h";
+ sout << "OXNZJ9+Byx7v6RrU/42lLyY6p2078QYHif06BBp2267VkKcRN4pP9LlS2JECoex4vg43X/dE/48f";
+ sout << "DbRfW8KeR5kSOnH9dDWcwdoco8MBwOV47KIkte6i3vj0BpAQZD+GFuR5EfIBxXuklMYFr7KRS9xK";
+ sout << "oHMGA00uxrV5VWrzCm5lV4l4oMQcv9/hqFTLKo7nlQP5yu/TyoF+OSXP/qKX7N+CASLfNtwL1Ux5";
+ sout << "fweiUkaKnLZh8f+bxh4x0/UO3H0LWyq07/1evSYUBQhHkzSYPhkTq2msJ+eFBc0+gpbOWntK37JY";
+ sout << "udFJvL50jNoZf9clWcqzxnK5M/rqMjVCi1zzboiC1vyxWPhR8QMvEMRZ8XpVW/cAdLz5R+M3DGms";
+ sout << "KCJtIpxrduXr5+Bq09jn/1oi4qro2/ikBRTVTLj4js+yaI2t0uE6XQX1PO2JwSHW3V9krhJ/7JJh";
+ sout << "sLH3xidX1mf+O/hgu6NU1p4yrsGjz6qTYOQSjU7cVsCMRxW8y9vCWh2PcumONvuWeApgNKkkQj5d";
+ sout << "c+8ftbo70YFtVWhKjTG4BHpNh6fXDC+0ZmkhTFEyHAwx0hF5k7217oTa7aKEQp2qGEROYxe/wBMO";
+ sout << "Kq/lLPLQpVEldVSoOzmFNxGTkOo0j/bjAtwqwEd6mA87f8PvCiAWLTRpPFla4UbU8X0t82Ur943f";
+ sout << "m+hm5CdEBtyV9P1uxMO6ez1SI5YezMPfMCkhpFqozJsPrjkPMIUSDc+WtF8frIfNsWWmjukFwFyB";
+ sout << "3UU7r1AHWLJlEo4g9XPsMks3LkFeQ30cwm8Lnlj4wAistdLd3HNBydGSxO48Uaya2M6dfm3Xeu8Z";
+ sout << "77+7God1knNpAnL7GFhTTTV7XcFxEr76Mfdt+KJTXHIf1M8ofe67hLrsT9FunpPmopFrNp69v2TD";
+ sout << "H0/SQbseKjykzwvJkK46UeJFxYabRHSgL67prx6jwl2Cp9JnNIco/hWNPGbFVaEcMbZx5lkinzvT";
+ sout << "KgwrJbVJ3oKnY2EJAnNDC2f1F8UpC1qQyEvhkA7g3yaJUKMF74TXqjz6BOhGmzn2c2GQBqzZ6d0/";
+ sout << "Ko5f97NNO360xzWgTIiLbg1sPrA8OllufpaQRxyqFzTlU/kSU2BDLWXM2Iy6tGUAWCUGIkMgOUia";
+ sout << "cXdp07NMyxlTzWBux4nmXRndTn9y53qZXjkeF87G+ZG2Q4lUmp2hunx+dyYVdOFWCePCYJ8TcORQ";
+ sout << "kPI7Jcacu7QjoOz652vsf+PQPsarO1KlyKqX4rFudTs79TVOYdHsf53Y7RIMqp1NAFDjAsyFPdq3";
+ sout << "YpOr3UrJu2RZm+eumrTK/JMHSRcbJuAyHJsBITQgvmisRy1wlcDqzw3k8OcfpkjFsJNPNaQ1kL7t";
+ sout << "HiNZMtrv3t0ER3+NZL6PnWWp/tN+ASeE5p75S2UyKtgLONa6xg+gNfU1PzxuqgX6CU1me3GLx/xs";
+ sout << "9pO0eUq57cy+gFcDzvTPw51WUrsaQhD+ayfUyRw9vpBiw34NQY1vMNReMgl6EbvRxFULAkx/oDFy";
+ sout << "wnPkvTkMobxW3JnVGL2mb1iHUKmqQzBsMk6zQKiqtasPGrzg9Reb2DYSVdLpZWCha1BI8ySpOQy/";
+ sout << "ndBNtz6DKHgIQ0lp2pzmJbU7JgqZD3UmfnKzHcjskto87KRz15aWYTnIFg7INMFMNUXqUYizX4V/";
+ sout << "I6UpRr7GvKsITthFaIdwb1AGzKXRRmv7NrsH0x8ip+p6mDp/Sb9dUG0N4ODEYfLlGzA1U3KbZAWg";
+ sout << "tfH2AF5+vVKtgUuuMH7XPQ9FBT8HwvqygWub9K6kLC1qwH9pK8YObWtrfOdTz0yfOwhaMo/kZCzS";
+ sout << "+CWcit3PkXtOuNXlq3oO7fYcRDPdCOFbUs/KV522grIRqZ7mgludKZqP9b702FVEGFT+7TbxjS44";
+ sout << "sx/F5YjT/XEfCP4ivZNjSYdEsQvSWfvnb5IBkjJafE8xnihUwcUNYYY9gUvKqZNm5XjKiTFLhPJR";
+ sout << "SlaNrK/pzAMEDwVzHWPeF0ZG9y22WsIFfsYgDqJwjmXzd7yLkKBBe+NuRPlvhh/Adtzr+P/4NMoz";
+ sout << "f7dcJzr/+VJMCqoq3tiRo6j5nOm3sylEvA7/HTethnRyHx494FMdSwJ1t4AXxrH1dSFNGOXWJ8Tn";
+ sout << "WMi25e99RMpe+Fy3fBygtCiXgQ5/sozmxR6LEjv80uoqL0sopOWKSKe+aGZVzzPHhkfJV/HY9N9O";
+ sout << "vJuNA1Cwp8X9OeFYzusBXdrWMfzTxfeYg6Qj7coKEToRF0SRuskob0+oWzufMPJVCCRRevu2BodH";
+ sout << "QWE5HiZMuR4SYbEgwQBnH7RbF9vW/DB57H3HRvRc+NBpbYZcWipQyi3cy1RwmSNOtexX6XdqoXg/";
+ sout << "iIBLmFENMiByy8AljjARQPUiH6OBU7xAY4zgiBrM0JCtsNlhnDuF1n1udIMnjmUcjAlJ4OkG9Q0L";
+ sout << "w4RvKt6/d7xijIvnX+i0+jH898Jhe+fX+vu9prCfPxnhDPCeDOre7g5xcTAxpX9PyoFww93kdkUq";
+ sout << "FAt7//v+bzkV8FvhUzso67ANCtS9w+ZmeEoU/ePml8oW2xGaOCx51hzfSzXhcvi6DQP70QhWGFKE";
+ sout << "lqjV3s5Ra5WC4P0Ipqq6PKuho8bJn6hz4nlhlLaSF5GfDpqQKzHxvxvDw0//PJQGNv7LoCu5xtmf";
+ sout << "u/CnU9wUfWie3YRDs6023yhdgyuY2nbSWSadumgv/zBNJH8zdP156zru/LLvr05hbn5QMlvdg3H6";
+ sout << "jS5SxCi/FXaW5sOvngedtvRwZuN20nHHZQIFLr0JebQGxOS3Pceh6CeSmslzrvflpnrFJJk7wKDw";
+ sout << "ponOE1ChzU50pPPl1Cr6vtz3mQ+cSSUfy/yj3jiIjVzs1ZRa73+iC3ibUKWzUcuZFeJtZ63UFYTL";
+ sout << "I2oz6V2ylX4Swqr6INVp1abOAWFWba12EP97P36KMGN+Srm5E/BoowWKhpy9uR+AqQVP+NP5BW/m";
+ sout << "02UQyGCthZMnbw7lSD+0Ihu4E/j0Zfh6K2vBz72vxGa9BW3aDUgNvLRyU4CyLf/X8Q5+73iT6Cwl";
+ sout << "dlFumHdywzarpmRS01qfzCT7WN4Pd5HKKNvq9KaaUOUQqmkXrrGaaIoNTAKHh04hhi6BF5rfueW2";
+ sout << "rOFlukiABYz2pLHwd8JCTUUH+l5ly6G5NhNWGdM9AH2tPxUpmqW2D3hmaF7k5I+ehdNQKHxnzXUB";
+ sout << "Wv7O540zfZEVkF8cGAuaF9rvd4GTvTSU/0hO9JerDpYPDcwu7V7JT0lDjjlVyf8Rzr/5QtLAvsmR";
+ sout << "ptFG+VFBQFzS1oSd0yQ5sSLnJbZcABQq5zK9kYMlSVg+DERu0yqSaxk7f5Kjm+KHLjoSR+9th9lB";
+ sout << "AydFXCQdhbntrBkbSjG5t71xVSyhxcazUYoeulumJbiDMo2Nz/GBvviJL3ZAAyq2D0PFXJsVwk+o";
+ sout << "0sSWItsGGLiiw55G5NN5KmQ/hxhbjxCMjzQ5ALsREiye7MPDdg9GgwA7xa7NdVdjprN8RxNlCS9a";
+ sout << "bQRBO+z+P+2MoN7tk6JIWn2KU7ex6R6FKjwHz+kU4lJRaJF8LzpujYtTw78zAgqS2uTPDGpHdfJ9";
+ sout << "uxW9x2IvyYg63TG7xBKS4+iFmSJGHsR5naozx3D72vCZ3jTe8D/fv8FlHOoPyYO4gOZgyC/cOIdC";
+ sout << "jM/EFJKHkL99pSetGn8KALo7QbrosHpZER2s1nhIXc/kfG2rq+scF0ECChECnN9sVYEzerYuNXzk";
+ sout << "nsAPu/3W0xYMg+TE0xQTdO8OTHsfnbGAm5ELN0wxTVfdXIE9QpYoSSRGtHphyFoKcOgRkyFHXMmb";
+ sout << "zPuwR4bRhvT/HiW/bPnNrOBL2qpeoMKmhRyhU/8FpgoYANV+tuh2DCWGSu+b/xgzGO9kuqoekBaf";
+ sout << "PGQjh+kV5tWT5u+NTO2SxkBaGLZkBK8j0a/h7CtCmwpK+7Hq6WyiFUgAUenY8FiZAgd/4lPXvcJf";
+ sout << "JV+e2P83P/iAnnfFH9rt48Bq54rTjuhgDJ1FGHmW6uzHqX1XTINTidVSukSpy8+hpZvAiiNrQfTc";
+ sout << "clOqzIsuuJVBivD5t9/BwKOp3dee9ZyDc9qTH9fjqkq8dKSjZjwTil0meMxI3EEhCOssrXql/+jH";
+ sout << "JjPHBao4OnlnblFyPUFDp0MyFP3OE3o7Wa/RYrhLuq+edYM9aKgdWzvSbJAn8/LGHDt3/iH5joVH";
+ sout << "UrMD9vp93N8RBsdbMY6hDoHEmHWXJvQAyVQpS/urgZbjbdtKT+vQKvwrRlUY4osNJ5fVGVDfY1qx";
+ sout << "+3u5BWq4Fd2UwsKRM8Ut6m4dm0yog+pr3ZVcPfgGsyXG5HZdyDpdg0AJSb/wOAJiNZQGtvZQ87jJ";
+ sout << "2Vk3fIVSb0gk2p4vINajCZksZCWordROndVW9kKviwD4QBpuvxTCgW1ww38M+0osHHzptdC/h98m";
+ sout << "tFXeW1AOwfG41mRwckQs0MWVn5Be4cUFiZQ+qkgH99p+3ZoNiGdk2CCS5ABvejuAiJ07wbiAzi5S";
+ sout << "2kdjxM6GgpBjmT3gOz3jvc4dgcXA6RZC+sbh9k3U7LakNE4PfZ/WME3qbN1nuj+9/xhHoa5/4gVF";
+ sout << "qM571ayMhfBoKsoChNxVxiQDwMnMkIsbD+1xUEr/9OzIf1fnYKU26pX94koCtsdxN5l0HH5Url3J";
+ sout << "+cSXI/XX9lOo/uUM5VW4eZ9aB9zfOx0/fuZTqcVxqkzUz8SH1gfOS2QzGBkoSDATOxVU++tTGsVS";
+ sout << "jvCtloGsRzz7cSOdVEyGH7Pf1PweTT5MIyrqdmVDRyYiYcHNhxJvTS7iEcL6wdwXS0iX8NdIp9uq";
+ sout << "NCrhqBcAlQZ8vKgXLe+FJ/oT0lwZQaF46SFEWjbvP8fm0xMVGm+pkaniNAVn2m7D1FADdIfcNTZt";
+ sout << "QjWrboY5ZfHbOwOl06gTV9JTQGRjFDUjy98D4st3sQUZBq2JaFJ32Qg+fy7knNSrpu7sHWloP+vT";
+ sout << "PvoJGbK/hFP0Zn5ZwN5V5UEbE2JzoJE91+VHhUwbh9TzNBxwnDroOxwpzHvJnCxnb8SPDKKrdT21";
+ sout << "n+U+kVkf+0MiLo/GEQMa/365TlPqVNJDKzbtOwFzAV4/001Z8oHQwWqOeMZtOGkgbLx+mSs/sfCC";
+ sout << "fMbMfcXXyjRgPYsG0JiQHXnB1AlQ7jdTslLgpTLra1uWB7PdFydbSd9xBrGJliq+s1VLML5vtHOx";
+ sout << "zIkRy3z/6F985ZiZN991fTL8O+dnIr7/bhRAfnGz9zjdjVhfMCSZ1qbNg+pDIFre1eRezr7Vi/sf";
+ sout << "/EAvYapgYXBpO2YHMivon5jd8BHIiDuMxvO3k8gtoc3N7cS4gRFbBX3KF4OY7st3c2TVBeXFGfQ4";
+ sout << "pdfpb7uwAfOLY02qrouv7egOIQkfvVGGtFHHWyF7Ua+rBmdUgSN7qyAoX5ImUCkJBfYWKpDyV+qE";
+ sout << "sl2Zv6TAlmoV1Ejb5zpSRGKTOZQeOL32IC4ObnmNN8Tt6PF2jWHKfF+E2EvDUnkvuryJgdaat1/e";
+ sout << "ROv+l2tnyxLcsudPd5IC6PX1PtyQ/VRXVjPdgALubsid997mfwVUEKqN6lWCnyxWevrjqybNaNGy";
+ sout << "TKR9jTz6c1lS/pvGyI6/tRau4N7yCm17IOPL4IS5LQxIrmZM5u4CJbXb66Jc+ugcFY1tLbh/2cOy";
+ sout << "+XriVPTbEGDQ4A5uj+7xOo5ZRdoTrdVVPtDk+dlVfKzXzxpb25S81YFqhjO2mhIAQUVimhDvfzJI";
+ sout << "3STEBOwpTG27aw//24pQ/l2/HG5fmjCFKnU27+lJU4OZWLVC4xyNFcC45PPCOcMbbGOv89uwVAzB";
+ sout << "grsyHpXH8piJ+i48nWyjJYRcMY7QruLJj0XwI/zyfostfynEtzCQ4z7izYem68epGW8hJIno9YC9";
+ sout << "ILlnQ3D1Q6ZuLS+DZbbYX5KtL51EGpOXIcURfvVEgUPpJDRszh3+2ftzLqq2kBq7/fp1qBVlX7V7";
+ sout << "FpB+Atuo0nScYLh2qkckGVz6FD+sd55R1X87c2nyoq7Mneo23ed3+fOWL08vOS8k/TRYm8sah4Mw";
+ sout << "jBMphehu83zxUzzmCxgyw/YqBpNeIvKOl0aG0QKJl+d/B6ZUujG2c/d21wxvGfhUdmPq0fIDY4f6";
+ sout << "C+j6/lZmgeQKQtYoAN6ElDRpTXd1A+3QqqcI4B6stZQR4JS+yXVg9cbekGvrt4QQs4JX28naqY1a";
+ sout << "2FUNMAiLZ2HiAOR65wSUstVLm7BfKhWmjwtsaC/0EW20Dk2UgnVOrBLnBQ9qAN4b7NmU0WonmxEY";
+ sout << "ojTy/G3EUpNlGyA8/vW01VWvnHXY6vXYFIqbr5vVrcva9uTYUR55ZqOoEwieXtBtjMbrfsnHYv8P";
+ sout << "tR/v9PeZbgs9t/KMYR/uMBEJ9AZiee7WVJ4h0btOaXK/46+XzeUtI5WcyLNL//5ryxuloF8d4dv+";
+ sout << "Cc9x78QO31N65ELT/k1U0egzJxgrw/3Hki+p9JU8IkTsW0KpGjEGZBOV2pgikBdJvtj6FAa3wRUi";
+ sout << "PJoSIfsvxzrV2luFEsFgl5yMEW90eOsiLKXcWDhqEEbulmLx2ij8UrCVCY56umeqc+LyPlDfKgrJ";
+ sout << "EZjImfmAt2Ygq1eC4diAMOmE1UxpFq6naGmN7qqepdQluKbFsqDlYTpOaqfems/zLJqkcaw70LGr";
+ sout << "VMp8Pqv5ii/0GDRXDBhkijv5WzyxkR3EypXXxNR/+1AiALmzJmi+es37MAcJrzTJXLa9VBqivhbR";
+ sout << "8dN5+0P+2LwViHb55+k9sXzIjOGnOk0MEWlYHOGjMRTEGFRTN7A9nCyYXy9GNfPK2JcHVf87/hHY";
+ sout << "5K2i4i7tUrCe2Csag8f30XMI6neY3ftCMT4Ig5IaZ1sFOq/T7tq9itnCcp4mwlEYPMyMIkG/F/LU";
+ sout << "hee2A7h1pyXJfcGezwMznUz7W2ul6nPiyNiukKwkyscniZUpLlaY4QEqucllRuJ/68AaZ4b/Oej2";
+ sout << "jyS1Ic2KncAmPZ+1Bg0neMcNSWquSJgYzaDClIpXV8f3PkHrr2uIsC9W3eNshopJHpqLMzuaQSHY";
+ sout << "2vAiF94VOhVSyUWpQ/1azlaZt+to+uWlh913iWJJ1W6/ny5AwzWh7M0ikd65/vX/nmzcWDNIe4FB";
+ sout << "dXtUgIbWZGSvTnb1Q0ff0C4F+XGSG/27sLrdSbmNv7IjZcqQJkNsqlIjOMUXKRPmfMmOD68qQomE";
+ sout << "m02IDYew+Ah0vholXhlgVIa1V5eHItbFm0krwNfQsxBESR4dEQMJbkQAE17x52EneJzQRaNjkDdB";
+ sout << "dCl8MkWvCwi4iNl6Mn5jQsO+3K2cC6fYHDRReXmp2OmWXlR600U+oSNyuQjNiUM6CD+q7IV0SWS9";
+ sout << "txg/d76GC3ELUb9MtBhtm0dUBT4hCjyuLqMAVhzzPLfuR8ko2hc9l8VziIHDGnusZKle7mQWr84t";
+ sout << "L/ERhHo94fQVR+BuogcMUEcFq0cAqYHWzwI41KVB/N77Tud7X5KuhGc5ulVJaPukTGGvqIrBDbBV";
+ sout << "HXFCuuptn8cr123muSyZ9qBcXcSs7DRnZ1mFO1LoxW7j+SsuyE/c0bUN7ndjGTUC8OiS+NC8Bjdu";
+ sout << "u6oxAUIqlNYIoY7EAPF0WphyKvId9I8knRWQUQhD4L2kk8yNvtYvjdv4udkJAUQydaZut/lnijSg";
+ sout << "Ph21q7/c5IlPo22ZIiPI+a3O3wkV07i6vAPoC3zYn5Vu6bFRHSSyolNsOrEvCkWwQ0oTCcm0Mp2S";
+ sout << "eiwjZU6/k1AjV5sbx86VksQ/AvKxU7RyMbeuElprxKJIMLdkghibR3x4clnKG1uRzM5c6eINHY97";
+ sout << "vYFAN7XsTbpmtA5GgHUtBWVJl6OYhBplfM/ZECAqOp0ZbBpEpfEntR/Go9qLPlXT7uFTcqxKePSv";
+ sout << "pYwsS8xLTovG/ELnF7/7NxL1ZPloXw7JXSPoSWEdbQ77qG6nOOYyeYf8i8MCkSC8tBM6rcORlcfl";
+ sout << "GTUIeRALSs6B63QHlms4Ev//nz2bSKv7BHMmrA1+2EI23xeZgiuPoKBfdCe/YxF5kXZ0PSlxsj2N";
+ sout << "7OCHsUTBiQrVCUoAO5hXZWAlSz93FgBGkc8bh/d6dLW98dXvWPxLdq6vx7URXleswpb3FPFNm8R5";
+ sout << "Q6WOEu2+Y7ilKgIq4yv2259Heqthy3z/t3QuTfa+lmhTEpLDyFFZ1o6ERsqYmMrkPM5DoPn5K1BS";
+ sout << "8svZoTTyRFw6yxjoVC3rk3ICe904M/cuuPxOaV6D3/7/k2/9Qn2+dDWV/Kv/HnH9kR5L/YjZ924u";
+ sout << "yI4vfT98p5Jbxd+m8wguelLfXVTz2dNjBQ9fxfZbVWMJj2Eo1BjHIAXpFjE7g9fog+NbIqnlIb3J";
+ sout << "rBh8jEGWy2lNrNZXVzYly0z4d7qmrcbGI5FhlWOkKBFAdp39ju66kI39BZiM/RoTydqIQ2iA/eZX";
+ sout << "wqgzqMPQ/LrpImeroHcY3tMd334UHnzDDq2rJcqreapzK+YM/saPsBmiYWs4joiDCjTJcGuHOroE";
+ sout << "PIDb3yGry6Hov+GNqI/NpjFMQIrEJlR25yBiunN3t4sAcHQJzT8OHxrDVV2BWGRbagCMqWqeN7KY";
+ sout << "ePwovpts9a5QbgncQzbGT8X9p5WQ/uY9miOJACWeHr/kZXjQt2ngGBQdOm9i3RfYW8NOjBDGtBpJ";
+ sout << "Ys31Wj9mwuC7+o+4DLfqtfXrjW/Or4zJca7EkuKJbRjlicYSyMNSrQPjGxq8qYkHds1dEQM0JydM";
+ sout << "NjFG5vLb+nqNRrABnSVkuEl2W83udqnjDE+mJVEnfwHnPxF2k1Kr2nmxqO54ZUranYnyggZxrvuu";
+ sout << "HGkg62IpJXv6u1R+7rF8XRErh36r2lkmps1cCkmW7PrqaB+z/wExOH7kDZG4cMJitrTDywtYsDVu";
+ sout << "xltXSqRBUTH/nxrq/9EiQOM7j/ITCoiZJRfA+G2hW4srArUW8EXEy1dKfOKrooxrZnGeEh2E5sHi";
+ sout << "Dib1M9iQlTCc+BZFPqvOv8lM8uIe4ylVvh5DtyzcKgg1ta5hj4nTKL11vLDBXyqBCVz288zqy+Ra";
+ sout << "seXn0vPNCk9fsxOtFyjUH9UiE7sYcVB/SWYa662DLAvV832uOjFVlOEESlVhhYWb4nCEDZVnOnPH";
+ sout << "1ilf7LOgVi+qHmMm3FS2F55YclALS9CpVmVbt4ADpgKaE8V0TlI84mglvHOJfqE5duRDMfdQkjBV";
+ sout << "o4vxT6Y2xv49ARNgDI2J8yt0bxnQ257afzSUxvvlROxBrYYNNkQ5lPivD+zeWH5j/ojyxqF5iSNq";
+ sout << "Arp6ClK878ubKMvRPjdmrifFhSfs9vhfL3Ox0YFPBq3zKLPbTJEalN3Eeiuzd0dDSnUatLnV38V+";
+ sout << "wyxNsDDywi83kR+dulf2SytyhnCCKOHHstUa3M5klOVLCsrj5lL3CarIo89fqpqqY0H3gzosW+jw";
+ sout << "e+Qd/PTgX7FQd08oasrwptSX41xYXtTH/K/ndPg6i/YzmdIBvGuV+A4MltyzGXXRYxulYZv+OLOE";
+ sout << "9AIl10pH5amcenHV9Q97qZ2NAtGeBGcWQNpQRl7titOfka4CHpNBXjg1xm/go6SHCy2Lb220mw13";
+ sout << "x2kdIEa7b+bRZrXwYJ7CNHE/OuKclyzDvZHfwOrqGl2mfYnG78oi+Gr482vOBZBr5sYf2GxUT4lr";
+ sout << "7YPENdvyYarw/liMmmWE7Td9rTkHXTt3KvCaeJRddK63LIjQrOJNCalDytkGT2LfsY9hu5r6a7Of";
+ sout << "yspHZhOqBBOyjGXe4/D5nQqwpFfccywWBEtnC/+DINOvqpfqx9CxFAZzdjJJRlIPtK6erv1dSTEn";
+ sout << "AodulJz+SoMYUrOSyKPqQlVdN0ycHvLFTwspnZv/6NqNzV8iqYuIb/iylAww3BkmtbmHJBKpeRKc";
+ sout << "DVNWSOiFRb83QaDQLh+nfH3J0p8OcEQgN0XSQIamAOGuRPcTILCNsn9gg2qEwpgpo/1gL50XfpvH";
+ sout << "2SNQBJqD6DaZ1VwqzEyQXAw26niGJ83+UEB915mZR10FYo8mM3Et5WYyg3/0Y3u3+B0GHtF1lImL";
+ sout << "wrpLFhUdRBijcxzCYwuPwrbC6tIHnfV06rwehfR5Anq0cwqip1O+uw2Af3IfjWh0wImoQx3Cm9k5";
+ sout << "Z3iRoZ0+MttTVyFuWjHGrwVkSItkwzvzRL/UdeyTkRqSQvDM9zZiwNygcp8FrpdEBuxMmfC4zAyW";
+ sout << "y0yNR75+2NpI4MPxmEh6jvDJrsKQ+hxl7teqfPRRi8leqIvz305ZBVcrP5bHMcuj7Iun9znHdqnR";
+ sout << "ngddgfi7+SRsy5pQEtmhMoTI5Q3q7OB4I8IrttJPJRu5Y2HCUeCfmTlTVQD0iu/eXYeAbt9GXcb2";
+ sout << "LptTexWOkchMYcVh5qFWVmnPWjRa3X1nl3ildvrkqjTjA96J4G9sd0TwldCyZ/GglrM+SP55tvLv";
+ sout << "4MOevxl2gpNHipkZh19MiJpBArgBT1uyScDXrty46tWdIC3eKAmVfZprFbjswk6L9f+DmzDyeDlD";
+ sout << "v3mfZy7c0rZt/AIrReTIJYb/aWRCno4vyWww6AbvH1AYm0nWD3/jcZazTEsLGk1LkZwQ6hpXOHa7";
+ sout << "47lDu5kdU6hprzMEhGuNLdYDKf+Bk8I7sYp7fBn0FvpnD+w11jhINFJZHL+4MG53CzMqo0iiAbX0";
+ sout << "9ppZbFaOVCrNfqJaRWKYQnkcyCFFOsF8MCKeujNtUynXLAz258d669Fr8c4jl/nzSdi6Y5SMqdJw";
+ sout << "tIBdmkAHxdv6sCRys4gyeyFjVHDeUNrszqG34rEV/905CJn8JNTOtUB/kk+WJaxrKyLkGUMHQHWO";
+ sout << "N8whx74uMJhsg4W+Qpogy9uopqF7Unk/kCbuBrDzXR9+XjYwhFE6uteAbUJ7RgrWCP8929150lOz";
+ sout << "dk86E6B9KZjyIke0jrxH9AwH1hiOLkF8kIWVXdjTPgqF4Q5BjjIdSWhXWS55t2rpD7Hxg3cvOILF";
+ sout << "c6IoU/uRuxpoMMnSuzq+weYnEjTBW6SlnjXjkIuZaK1+2U9rWDaqEgTn2ip8dgS+YA7vA7+dh4we";
+ sout << "vR308ToEwblhv8vSWJICn4iyfaUDcFCXVegEzl4oJcLY0u4NAAxEVj8O4YN9XQcA51dADKZD3+70";
+ sout << "yfVPjt4xF1StFZAt8zZuiuh17/SxoyRZXSOZ4lrX1ihQI+mVIXAblu+LpJM+ugowwdnnBS/poJwJ";
+ sout << "b2W5jv3q+IFy6VJjYkvzUpckAnHGlQyDhYpyYARW6S8BcAox4++WgK6K7iYjgJVUxTKdMf3LmbWm";
+ sout << "UhoR8Xy3P6NBq7lzZRddjFQLZ1wtKBgvqjSdtXDFg8C4oUG3s1UKF5rLQ8ZC4EXn9kHCJI6U4IdT";
+ sout << "nVsNrF8RTfItEy3ji64JnvVGmFDPb3V0CPSlSrGwmiF9TeN4iT1OOWCXNfJyLL947Mpd2hOx1jpa";
+ sout << "52OVo+GofOhImcAXIryA9BoupDVR//+7iFB8qffCuz2ZyhAeKTvVg5/TEXsItr/9Mc4kbKUo31E7";
+ sout << "7cd47sykXhs+vdWU1qVpVkjDOmsHdnXLxkrL23+UUu0gUoE/zdEayg+yJ5nckV0EULpnOUdI6kD2";
+ sout << "r7PFc0abFaw0FrIV61f0AHLAYuFGL4/pZNXoHbMPcTjIOr5MvuneN2n32lqhHQyoZr7er4gm4n6s";
+ sout << "fPmgp/ezVB0uhb5Bovr7uKBjqCSSxwpyWLIioAUIy+J/bGQMqvC447PgH3Kkvkhmp33i0pEp1utN";
+ sout << "hXTHtnu2vdNNwZNrdANwSs8/hzRjI4qdcFVjCpnRyrcIATvkalWB6345vTSyg77XPO0m7q3M41sN";
+ sout << "me9p4AeLxlgRDIfkJrq27zPlYT+w+o27s3jXBS2MvMdSwl4CW6UyHCqrouaXy51PrWtFLY1LZjx9";
+ sout << "3R0xGbp9XZC9WRqiL91VMa9l/sTS92bw7urPeRj1FHh5HNyDSpaLEDHQiihXJaz4xxGbdEveyHW7";
+ sout << "4yhgD4sR0slooQhw9O6IaL7gjw0auFf+ty8jedYY/LfLHhbRGYvmdL1NiskwM6mdgPs/w1q++HFt";
+ sout << "u613gA7BRTxRw9MIiriCtGyk4U8uO6PnGGqRoXNpnJXE9fgl9Qdoy6N+uw2JTIMcE6btB1lbjdQD";
+ sout << "nlUalgZMbXzm07z+MNNNGSc5Lc3ylAJ3v19GL6qPYYvDtXcXC8lPRSmeZu3k4tDZ7gVlokrSewYR";
+ sout << "iQznd/Cq4w/MBXFRy5nbtKMeAfQOEU0KTgcOPVYfd4sUJiQixYOyDpRjWHLuEfCXoXEbLIBLeJ8j";
+ sout << "6YHwyOMMzxBepwBSxTNRlNnY5GF22kwhk/KUIB12mmkegsiTSfA4Kz3q05i7KF93WZB1gDRSkpJ5";
+ sout << "DgtN6fALotQJlAdI7CgKxiqkTD6YD+wIA7g/bu7EwH5anE+r9mBEimDxrDNyhCSVwfYPnFmi/HLk";
+ sout << "CtH5msyO61QCth9RCpOKMsnqHH2oqh6XrH+D6FjhmFxqlzp5PJ3SEybtCY25xxxnmwyJh0uDcAzr";
+ sout << "a1EupoKzlsY8U8kFdcmhOtPOnSgQRqUoLQxZ0RUixPiKFI3ikbai5/ZNNlt7Cl6XcOWxnQn1XLGh";
+ sout << "7KewlqwiweypCVOk1D6NHgTdfCGzW0NWYrs8cqzc47cWDSMQbn8Zzr9LMHdjq1t5VoT+0pyasBhf";
+ sout << "Wxih23uQlVfaNO5SlxpMPuW3TFpASdhxiXVmJbIl/j02lo5w2MLYUUouGKT/WeTr2f2R1kNZkCcN";
+ sout << "44DdifeZYVqoUrAV3etS4Py0H6OHDtAnFmU7983u/bZ7bpkfvFl97zvms5D5JWuFQ8HZTZikTzIM";
+ sout << "uxDpDcxkFz1U24O/WnovgMCipjI6uV39rjWr3qXb3qzc9D7Fp+jh3eg3F9C/SeXY9Ru077P9mAI2";
+ sout << "oRgh+2hJ86+1/YdCetlEVgmIVVVGVbcZWLNoHISNo2lnH3fSDcfWTRekNBlvUgiAE49tH+av0SN7";
+ sout << "cxjm3vWlWv9Mdt1BvZORAk2sYugBnDJZbB+F53rKioLbUNdlCG2HcjDboLrRnY//cxOlOARg9UYB";
+ sout << "N4+HueNJApuqkGhItKHRMKXWXWXKYkyN4PdPicVFpdlxwoeXNWMtNvUbOv9oAox2HwWqFERO9JGa";
+ sout << "wSXE2oYyE0+BUUUPq4Bf0HobSR9yOVj2YmgvvEv61uS/7rDiSHElMnyrGnOpy1Jk9Qc7BwDJ4iJt";
+ sout << "LH0qQR8w6qXJcDajjLT2dYkzFYj8Hl4iglGCRuFTKjhQLp/E1nium2AS5aSlvk2GwX4SHEnk6nAP";
+ sout << "zYbc2wAbehdVW48RzUWWSW62Zckj2YpDSMoHlPJhysfxN5NhGzoBag5D28vAsbmuOYKw+aDDg7/Q";
+ sout << "kmGxNMjXuZ8z2dUHAXA04UxRx7P4kIDYHrOPyd1s+V/Nhd2WSodXW+X0N1pC5Wv8EYYeNaUke7h/";
+ sout << "8w83XCJ9cHSUO/PTRY8VLd1GX0UFkPb4m3Vgbv2ARqK+ZoZ7t09USLMz9JG9MeD3+J0vL9jShQW3";
+ sout << "+4j4G9ZuiIW3VlOu5Qm7jdcLEMzd54mqjC6gYRqTYNP+1P3LtfVY7nhRdxR6S8Zt16B1z+hHtLsY";
+ sout << "APWNCR21V6k3R3MjFIit1mBJZDLFFM2OEAYZW+SQ+TkcSueb5xCyFK2gwynzU6l5/CSbaudjWjsE";
+ sout << "hpcqZTmHsv+ertehndIaMes/Ihe9ZWf8KJU8sYDn4gV/A/ZXesRLMDtGsTKTywN99GdKi1yX1vpv";
+ sout << "ugSgxjMoplA6lZHmz3+sEUepfpLVQxpBQ7OvrZrhBuf8GxgKRC2C9LbdKdq8+qM/qjuNUf4CKz13";
+ sout << "OZfp6K89LPJx4Qua2uEKtoa1i4LN3Yt5urZz6CZmlyZR8/jo2e/PBqsKc5zP7SzJdQ3fELngYdUm";
+ sout << "HJC7uE6ElkbQWqTUg1Tjm8W2kGmbahkM6eVYps1yVrWqWQvFG/m3IUUrIhtvK5JwzlRfH13GIevg";
+ sout << "cyQl2750lWOaewIa3Bni58GNVuR3icSmcf6hZ2PbeEdnnxMW8oHUp/cWMVHmZdG+AA==";
+
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/fhog.cpp b/ml/dlib/dlib/test/fhog.cpp
new file mode 100644
index 000000000..88377bcc1
--- /dev/null
+++ b/ml/dlib/dlib/test/fhog.cpp
@@ -0,0 +1,684 @@
+// Copyright (C) 2013 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/image_transforms.h>
+#include <vector>
+#include <sstream>
+#include <dlib/compress_stream.h>
+#include <dlib/base64.h>
+#include <dlib/image_io.h>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.fhog");
+
+
+ class fhog_tester : public tester
+ {
+ public:
+ fhog_tester (
+ ) :
+ tester (
+ "test_fhog", // the command line argument name for this test
+ "Run tests on the fhog functions.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+ template <typename image_type>
+ void test_fhog_interlaced(
+ const image_type& img,
+ const int sbin,
+ const array2d<matrix<float,31,1> >& ref_hog
+ )
+ {
+ array2d<matrix<float,31,1> > hog;
+ extract_fhog_features(img, hog, sbin);
+
+ DLIB_TEST(hog.nr() == ref_hog.nr());
+ DLIB_TEST(hog.nc() == ref_hog.nc());
+ for (long r = 0; r < hog.nr(); ++r)
+ {
+ for (long c = 0; c < hog.nc(); ++c)
+ {
+ DLIB_TEST_MSG(max(abs(hog[r][c] - ref_hog[r][c])) < 1e-6, max(abs(hog[r][c] - ref_hog[r][c])));
+ }
+ }
+ }
+
+ template <typename image_type>
+ void test_fhog_planar(
+ const image_type& img,
+ const int sbin,
+ const array2d<matrix<float,31,1> >& ref_hog
+ )
+ {
+ dlib::array<array2d<float> > hog;
+ extract_fhog_features(img, hog, sbin);
+ DLIB_TEST(hog.size() == 31);
+ DLIB_TEST_MSG(hog[0].nr() == max(static_cast<int>(img.nr()/(double)sbin+0.5)-2,0),
+ hog[0].nr() << " " << max(static_cast<int>(img.nr()/(double)sbin+0.5)-2,0));
+ DLIB_TEST(hog[0].nc() == max(static_cast<int>(img.nc()/(double)sbin+0.5)-2,0));
+
+ DLIB_TEST(hog.size() == 31);
+ for (long o = 0; o < (long)hog.size(); ++o)
+ {
+ DLIB_TEST(hog[o].nr() == ref_hog.nr());
+ DLIB_TEST(hog[o].nc() == ref_hog.nc());
+ for (long r = 0; r < hog[o].nr(); ++r)
+ {
+ for (long c = 0; c < hog[o].nc(); ++c)
+ {
+ DLIB_TEST_MSG(std::abs(hog[o][r][c] - ref_hog[r][c](o)) < 1e-6, std::abs(hog[o][r][c] - ref_hog[r][c](o)));
+ }
+ }
+ }
+ }
+
+ void test_on_small()
+ {
+ print_spinner();
+ array2d<unsigned char> img;
+ dlib::array<array2d<float> > hog;
+
+ // do this just to make sure it doesn't crash on small images
+ for (int i = 0; i < 10; ++i)
+ {
+ img.set_size(i,i);
+ assign_all_pixels(img, i);
+ extract_fhog_features(img, hog);
+
+ DLIB_TEST(hog.size() == 31);
+ DLIB_TEST(hog[0].nr() == max(static_cast<int>(img.nr()/8.0+0.5)-2,0));
+ DLIB_TEST(hog[0].nc() == max(static_cast<int>(img.nc()/8.0+0.5)-2,0));
+ }
+ for (int i = 1; i < 10; ++i)
+ {
+ img.set_size(i,i+1);
+ assign_all_pixels(img, i);
+ extract_fhog_features(img, hog);
+ DLIB_TEST(hog.size() == 31);
+ DLIB_TEST(hog[0].nr() == max(static_cast<int>(img.nr()/8.0+0.5)-2,0));
+ DLIB_TEST(hog[0].nc() == max(static_cast<int>(img.nc()/8.0+0.5)-2,0));
+ }
+ for (int i = 1; i < 10; ++i)
+ {
+ img.set_size(i+1,i);
+ assign_all_pixels(img, i);
+ extract_fhog_features(img, hog);
+ DLIB_TEST(hog.size() == 31);
+ DLIB_TEST(hog[0].nr() == max(static_cast<int>(img.nr()/8.0+0.5)-2,0));
+ DLIB_TEST(hog[0].nc() == max(static_cast<int>(img.nc()/8.0+0.5)-2,0));
+ }
+ }
+
+ void test_point_transforms()
+ {
+ dlib::rand rnd;
+ for (int iter = 0; iter < 100; ++iter)
+ {
+ for (int cell_size = 1; cell_size < 10; ++cell_size)
+ {
+ print_spinner();
+ for (long i = -10; i <= 10; ++i)
+ {
+ for (long j = -10; j <= 10; ++j)
+ {
+ for (long k = -10; k <= 10; ++k)
+ {
+ for (long l = -10; l <= 10; ++l)
+ {
+ rectangle rect(point(i,j), point(k,l));
+ const int rows = rnd.get_random_32bit_number()%11+1;
+ const int cols = rnd.get_random_32bit_number()%11+1;
+ DLIB_TEST_MSG(rect == image_to_fhog(fhog_to_image(rect,cell_size,rows,cols),cell_size,rows,cols),
+ " rows: "<< rows <<
+ " cols: "<< cols <<
+ " cell_size: "<< cell_size <<
+ " rect: "<< rect <<
+ " irect: "<<fhog_to_image(rect,cell_size,rows,cols) <<
+ " frect: "<< image_to_fhog(fhog_to_image(rect,cell_size,rows,cols),cell_size,rows,cols)
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ void perform_test (
+ )
+ {
+ test_point_transforms();
+ test_on_small();
+
+ print_spinner();
+ // load the testing data
+ array2d<rgb_pixel> img;
+ array2d<unsigned char> gimg;
+ dlog << LINFO << "get_decoded_string_face_dng()";
+ istringstream sin(get_decoded_string_face_dng());
+ load_dng(img, sin);
+ assign_image(gimg, img);
+ dlog << LINFO << "get_decoded_string_fhog_feats()";
+ sin.str(get_decoded_string_fhog_feats());
+ int sbin1, sbin2, gsbin1;
+ array2d<matrix<float,31,1> > vhog1, vhog2, gvhog1;
+ deserialize(sbin1, sin);
+ deserialize(vhog1, sin);
+ deserialize(sbin2, sin);
+ deserialize(vhog2, sin);
+ dlog << LINFO << "get_decoded_string_fhog_grayscale()";
+ sin.str(get_decoded_string_fhog_grayscale());
+ deserialize(gsbin1, sin);
+ deserialize(gvhog1, sin);
+
+ /*
+ // code used to generate the saved feature data.
+ ofstream fout1("feats1.dat", ios::binary);
+ extract_fhog_features(img, vhog1, sbin1);
+ extract_fhog_features(img, vhog2, sbin2);
+ serialize(sbin1,fout1);
+ serialize(vhog1,fout1);
+ serialize(sbin2,fout1);
+ serialize(vhog2,fout1);
+ ofstream fout2("feats2.dat", ios::binary);
+ extract_fhog_features(gimg, gvhog1, gsbin1);
+ serialize(gsbin1,fout2);
+ serialize(gvhog1,fout2);
+ */
+
+ // make sure the feature extractor always outputs the same answer
+ dlog << LINFO << "1";
+ test_fhog_planar(img, sbin1, vhog1);
+ dlog << LINFO << "2";
+ test_fhog_planar(img, sbin2, vhog2);
+ dlog << LINFO << "3";
+ test_fhog_planar(gimg, gsbin1, gvhog1);
+ dlog << LINFO << "4";
+ test_fhog_interlaced(img, sbin1, vhog1);
+ dlog << LINFO << "5";
+ test_fhog_interlaced(img, sbin2, vhog2);
+ dlog << LINFO << "6";
+ test_fhog_interlaced(gimg, gsbin1, gvhog1);
+
+ }
+
+ // This function returns the contents of the file 'face.dng'
+ const std::string get_decoded_string_face_dng()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'face.dng' we want to decode and return.
+ sout << "RFYXmMpdiStV6dVZSJkJX8t7GVavYwTD+Fn11ZjivhnFQyvVJ5t39yJYrK6Qh6K58ovzMlgPiBLV";
+ sout << "nd+ZR0JYVCVvwRapp+dznB9SG9dJbBrsYH68k04uOs9ehP8aK4/EXvcZG6s+rL0rnhVAf7SxL7PT";
+ sout << "r/11jIuASMa1daKZjAm5Sc1icGXG2FJjO6CxM8mOzWJ1ze69MPD1bz/QYAWtMUqUUIAM0qOPHY0x";
+ sout << "T8tdU+Vo6S6E+8dJpV6a6iDdocbp91meDQcT0/kadhC2tmn0eZoNulTn5MtmsmEeuPI2lLLcRJ9P";
+ sout << "yt3c/OJIzI8FaDzYG6aWJ/yBQx/DJF0avAlh7V1UmbD8O/dMoF9nUFDwnhGyS6DYfTXxCYgVgoj+";
+ sout << "Ik5RLHY0U/DhNTciFaLX41/MyIt0xcGtxhoVcvwkfIigKnYQsYfNpRdUWseRlZ1KYaR4Oc5B2tie";
+ sout << "kH3e5AhrY/HtffCah0sf6MBWJEi7CH9AnVLDQefL8Ph+qCWJGf7cGnM/oAaHQCzHIHVi+mK6EBnN";
+ sout << "1NDrzbdXmikwYneB3LUZxCLKZmxsFduB2HgiS0A+tTK6IYc+jqCHqz8N6Gw0sSjAK7rrPDTvxhSN";
+ sout << "lX3f6E2IDfVmyvk0l3RhuA1PNEh/nlKR+YxcXHyYW4wGf+UfWScAzKGxrHLxLC7LQycCEaCMkU92";
+ sout << "SQV5NSSlwKYKACabK6UJ3gGIpvuQK2Aw7VWmC0iLczqgWsX0GKJR0FAcVL9Ed3nV0Wd0s5BkjBsr";
+ sout << "RbUKzw11Qu0toj6BNfwXo/5cY2dtjj93a+CBfNrSEuFyJzZU7cn890c9m+q8C41p+wQdf4pFpjcV";
+ sout << "8Kz40Fyt8KtxItWSsACIwmUO9h7DGnyGskWBYrxgDV2VVlvuPAnnSCFPkbdsa/pfnohUq0C5a/ii";
+ sout << "BjASduPdaBHpjZ64f+TIaXNAGdrFiN61W6e3fOx4fLFlzPQ8szyWuuDh2hIz1FMflbmu6UOEkQji";
+ sout << "w+bwDDJ5OUFmY/00+3B0XAFmj7Pt8OQ70lAVLcX5fC553diQJzrrlJ5p9/8+ILln+oleUVJhtp2q";
+ sout << "VCZ9XknXLjkQik30M7orOj+tZt7HDgC5sz/wHU5arOL3nIX5IuIHBJRlB8dERZgoPNQlB090rItP";
+ sout << "MuT+Hyr/eR7Kcux7Fy2CoMxcIfWEXvxQoolLKC66q4+SFirdMRjXuwbRXrUBbenmBfMMNDAOkQKO";
+ sout << "Bi7d8t1wI9ulNbACtqLbmPjW6iabc0yM4g69cZjRx/JYhV5AaykROJxCP6ZKTw+3ddAht8xoyHLN";
+ sout << "40rB40fwEXIvv7qxCdCa3h6l6IRV26fOLdcew1G0qjPORcKK1TPhzmneYvhPZ1m0r6KxWNEnYcFq";
+ sout << "WhDGNxj/05eBy2qIiIU/KUPhxKyipF0ekgPoCsWT3S8edYjoaIl5cI0TNpNEwKGRLQeOLBDt+MEh";
+ sout << "z1yKm0i2jrtxDBpYf5FW/Fln/XJAK6z9yqSDDTDwQleabvRHDH9bc54bLc0TL9g7/eIj9xcshhaB";
+ sout << "zbi7baB/yUnI1+0N6CZ45gV3BcD5n2QLiHME8wELveiMxps6MTf3SdKSRZJcnoVfN4AGYqQV42ec";
+ sout << "dFB9y8FLZVL3/8rmB+XEu6YoiGcNK6iATLYQfF0GFRrur0Q6bQgdvXv1uZKtNfYfznsAAu/KBdxX";
+ sout << "8qskZBMGA3LxJC3j41VW6Fviy+XUxxcmG9ykbf0COJWDul6ZQ7iRI7rn9EpFIYBM1lKzjdC0UFTW";
+ sout << "yDWEE+mf9y+RZdlxHdROFj93FNwzSdzNr1yjqHvZHBZYiuArHEuDPXdxqVRePcID4EHzmpDgWFwR";
+ sout << "o5qqDxU8e9UYfS8SG545SPZv69SJVJKld5fQLZ4FbcCjv7wTwrOKTROvurKkxopKt1n69BdDA14H";
+ sout << "mViSyK22xK/F7/ydjLoqx6aJ8xyNpoUk6XIeJ5Ei2Lhk84VQk9dxzULVy3KsfRUrZCTTi4YiXkHJ";
+ sout << "SmQx4NQKqHR2IOgnJBZuNG9J3Fzv3NKhQpmKL0ZbYLXWdKP9FHWUR0x7y8f74Su+GrplBsjh9NIm";
+ sout << "QdaKLa3NvJB1TML1/GNcdJVZUuSaX0cQn4bbumvtcENVbC9u99fGnsaS5FOu4AHd3338zLUMy34C";
+ sout << "OpJjU1c/IElgyKmaGYlAolgqGU3lixhxPGBhUlXGfHmST2ZWq/l6NxD//HQXRaRUiQGQzWCvhzOO";
+ sout << "ywUlVzl9eJ5e5cdLWvffsPRzBgRMrdHJG4TbSuLAREsSD9QEGab3a6y+qa8T3Si/1Ut+Sn2QvPh2";
+ sout << "meqqk9g0fRWtrWxcnbUDU6zMlk36L/o/y5inrHdGY+ixIewhI0n4/Nl3wD96SRITcEVSx6K/BVot";
+ sout << "+qIP78I6uk+miUF6MW4AnFyCe1wRNyhT48638KIphSQSKdu7TaBndi2DNgFFvWrm6/cPOqkmCzGC";
+ sout << "O22uwHyuY9XhafswKLH02+VD24PIS/Fw7JMP+KzvfCHQd4XxxdsISe0/cjwg26ZfGcnULLY2E+dX";
+ sout << "LjdgCxNyFBzFTQ4gB4QExF0dHu+SPoo5T3VAojJbYZqIelFY+u2yQDuS4HCUISPkwuLHXHbcBuwg";
+ sout << "5TeuFhyBrlwxHQC/OPACmQJREImiqpzrjmh5QipeEgYHK3Zc72tYSeY7eTzS4jj0eRQ8KiNIGSi2";
+ sout << "2LjzAfN2Zm7HGbiBtKZVen96E8HLcrd3nSWnizfaLLWTWB3zu9zz9/vFdaa3TlO6BidYsKomTCgB";
+ sout << "wy8yMeykE2qbxgrpRqEqmOkrOI9XtTTJIycfAlwBwoFwuqvGIPtFrYmC/MwRMCphg7acSRcjZg81";
+ sout << "5IEqpoq9ca7Zc3s4foteVMCJT1A+qmNAJ/j7IoyeX7GnlM3jsqpYt9BmKfbw5Dr2JB9vzroPV++x";
+ sout << "UN2VXRPbahjbIvrTULpeBdmlHU0i3Ya8H/C9RY6c2DhImZ1gDjgn0jQ9GC+CsZpiM2xBvfZZGOEu";
+ sout << "c8N8pdo2owD8s5q2G5ZCGNdME/AG+iIlb0P00AX+XR8FYhxKb3y50i1giM41mnkKM/WMGFAnpiuo";
+ sout << "YordYSi5plePBnxBfd1Iq46PpsD/n/uUTZMHs6TGp1hM6QriyEhOO261HNHoU+n8m1Omz2cfRJyx";
+ sout << "AuFLwHSEqvGCSmslmoDpSg2qOaIWK1LWlN+1sYJj18iL4GRM0A5QzXaS0RThqEgmPjeBOkFBjfSO";
+ sout << "hB7mb3sDbY49qbN6P48bGV+yF6y34gYAiVkm2NksHzN4ovwg4O6WMQZwEhNk+4gTIzG69jIm6Hbn";
+ sout << "2l48A3CYmn8gcjZw39nrlSxpMf7KPkRsdvGmc5Qx9RjP71zH/KJ2TXP0xxzsaGgmqzXfey5l0Hih";
+ sout << "XZtfZw8Y28fHBfm3bnIncS4w9S91no+RYMv0aqc9ty7l+Pa28ELwSgQj9eP4u/i5iq/GPmmSxiTd";
+ sout << "Si/eeyK1RFJEP4Tv4f3PkV9Js+azu8BbtU+BLO1FBlVg3CzXH5Pc5FMujLdmlqa495hTmi8YW6Et";
+ sout << "Fx8dkC80mYFGpVjS+B6pcQLbLBL9gmKzJf4L94/gXZ25BEDob66+XOaRnJ4RkSAN2g6gFJB9lJDh";
+ sout << "rLerp3kP/ubPCvcFywuGx3UjJuwFNHE9m62uiaXFU4m04Kc4n7ccHc6hYUkhkY53v2Qb5SDx2qCf";
+ sout << "Yg+PWVXujfYrqxRHSwqtV3yX5kMrtYsYpygb7crweOt58BWUa3duyo23UGJHaCwhGwXat6PEC5DQ";
+ sout << "2Oe3LVJmc8eYtD97mHKFPhptBl5u2Bztb3zis/oNj1NdMjnDrNuscEAnrpk1CetvHKLglK63Zo/D";
+ sout << "rf6SJcmGR2h9g6wAeV7UdsfD6AvteiPj5sl4UuY9x55pP3CTTYklBO1MaDd/XO3A66uMh95RZVGr";
+ sout << "VWDd/uKL+rIuI+vKjz8rt80nv3SyUrY9fbftPdK4pBaVnIt73yZrrqv4Zr28H8XpFFQAV9BPlC9o";
+ sout << "a8G+AFx/+W2cSfo9r1Uw7npVvRTe6TtIiKagYUmWpx5BfX0VH/VAW0FUh9oiVfx5rm9eaxfSQnD6";
+ sout << "7qBINPxsKq+ZDSXni7qfC3J043Le/uL+3XUqsccvEMoU65akKC3lmw1txoUukv92oxyqPX0eOGsB";
+ sout << "AU4JdXCldqjU9K3QhyCvv80ZWotGfUr0TlN1LVZqcF2iq3pX1UDOBsPwz9v0QNg8Bmlqy0Vs+MUj";
+ sout << "nMCwU9xErzkXLsuVaG+Llk7mmAl7C34BF9O9qSl2kCmbQYoQ87zS7gm/pK7aKGNsICHrar6vlsKo";
+ sout << "BJA++/8XKL3nseNZHzq7hKHnOTzagP52MRf+TPXbTVjQPKnCKVAZJcsOlkmuZc7iDnLn4muHDRjg";
+ sout << "y09EYcYlFWhLAgsWmatQBsT028ytgMNrQGHDJdjuNkxYfPo+/91ijaaBiey+DgrUVn0fm20k6/Nm";
+ sout << "colrwPwHrK3uOdgBn2ysDeUXU8NLMtR94fIL7etQ9tlUuufwrxEL9zYUM8tpks8HDR51xgTwUOVo";
+ sout << "DyGFzOdYQRzwi+kkEPEwkpNQbB258d5w9G5eR00P8B/aSjm+w4FU0MsXM0GgPxnQ+gTpS1cezLTn";
+ sout << "eelvJYiq/IInLLxoCXycZFPt3WFQqOBpcs6TV/QucjI/5xMZtP3JHUFv16UKPTFI7p9DF+8Ch5HN";
+ sout << "gWXCnRSPdYR4ZRid+Xfzi0TvQsXV6u6PaE+H5MpyNMBWhCwxb6FdiLUW0BswGNpHBaFxjB26Qbmv";
+ sout << "OW+s0OuXDvKigjQRkeaYawjRAIAN/+CEYR3oUad2HyJ5Ybr/lRlybQuuIqBhuvpkYzszS7BqrxOh";
+ sout << "FJYaivT6r3HbHjaJ+Yz/zNW4KsL80zYkPMP7QgcbbSfE2mAavr+ciXdZBqMMUR50sDNLxep9+hoa";
+ sout << "ys9wl75QMdx1jn1qn7f04JMSjCyZ7M4bWSyTW7VEr+NBBLmiMzhI6Ufh1iCUpvrIDSQwSDUL88wt";
+ sout << "oSiouRbqizt36TldsvFV6afdLgjRrp2cb4vOQBiltwnY06JraGZnsrb4UCfHZhxd8sq/invK9tUd";
+ sout << "D3z8hYyLGbS+3LBCK85r74IYvCuhoUp+KobIZPhvWuvdjmmq3SAxIKHNdLC5hnLVMhGJUrckc18H";
+ sout << "9zK53uB3QXX6zGKK62Jph4aOdJoDQaPL0K/yHgn9UayEhH/N1uj3Ao39c05puaxzcSotfBeS5+6K";
+ sout << "WYyOOMtt5ikKz79qfj6dVWge22fxXUc6yHYfdga0IbYWRocIx+DuyUZnrRQHihNKgYpvF2vhCX/o";
+ sout << "R097oHI4ojZFAX/ZWJ7igJvX7ChiwTjK8KDk+vJ4SUd3IHXaiLkkkd9p6tCuc9Lw5jqWiGrrQKuI";
+ sout << "7AmGsPFU2EsfOzmwdZctDGXq2/IutVDmwGiucpBKsRN4y12Q1FWKpceVj2q761LfDx2qJoeZKTPZ";
+ sout << "jHPdXnGKcWy+DM6GoH9e5jP4CW+HfdHe474bHfLDbP4NE1oF1vdh4NcLy6woi47hg3FS60z+wePD";
+ sout << "bWq29WsSwU5oXq58nMxKOBiMcbGFrkOme/Z59Ybi7Cw1+U3nGE3evCFyVMC6g4f/jvCyWF5I3Nm3";
+ sout << "OqmkO6fmZ4ahql6C+RwfdRM8A3FllNPgO5riBNX6RA5xKj+JS+OZUrSSN+tUqcgN18IlmLBExEUt";
+ sout << "rdG06PKy+WM8Cju3gtbOFX43H4URr9CQcDxWbN6NoqgF8k5a/4+xf7DilfGJg0E2Vu8GG7tmFSU/";
+ sout << "LS6gtfLOFyEnQkTzqK8OhVPVLT62cEfCZN9ZY3iKQyZ+VLQhxwarUAgqeNAMXM40NBJqnUIaaTKa";
+ sout << "ryhHefUHazhfVgx2+GikVF9wvMobCvvP1qYONlL9EH+ufuLEw1V35BYIIClbrC2uMrnF0H3QbuJQ";
+ sout << "ma69tq8TDPkyDLiaczKuAxUzJoj9reJOYGYTxzP7AQKmmEmEZ2cX6+2klWcRXv23XXN8Ypjjnj+d";
+ sout << "fTdzxV4kzcHwOYMsI92tadahezCm9uOR0d8p9IH61QQSlUlJw8tX0TpGkNhZpv23STjQhb+uxzAX";
+ sout << "1vYdYbPOenr5vCyhnpp33QezQj9cLhSv1WweplUmZjHcJTkPBdflRA9AuqxDVVnbbofXd4EJDC6k";
+ sout << "u7xBoD7EKC+kCEkx7ygj8Gv5GVKbgy1js4gLuYwhJ5aqdNpqm881kkxntfRMluVcdH3IGAUzWR5w";
+ sout << "26eq7Je4Ttr1cC/xy452i3pJocbhCqrNUG85RyB5FXHAv6GMvm0rUIa6IyC/kfis+sQsdYkQ8GMQ";
+ sout << "wL2s8fdDT6l38N9JbRNwdRv8Xa9QAjwcGNbP2v7tAzM5MyhHW7FImYVAaNAaLbzE8v95zeGpT8Cl";
+ sout << "CWronhkcJRab8AKP2UcqAD+mW1hVEAqyDe7oWoZziKa2G5aW2vs/WG0z+NqL1zGvUekDcmJ5L4SK";
+ sout << "XgdQgxMb/1k48YqYQZFtQrIqoBbYn4qPeB7i378T5TLcCgB6SldsFdlNzs/czN0doroozh3W+sli";
+ sout << "d15Qnv5WMjOinjh0Ybt13wcUzeT2p0ovTtYLoiYAhDeAibydJETLdcozfpXFIJNUSoH6TcLge3tr";
+ sout << "0uVP92B1O+n0MibJvLsLUKQ9ueIiHgZb6bUSUixAg89QCDRLCZgkg24DLZ4MMTg7IRfFm2eR2lmJ";
+ sout << "Erpe62rf2+JE5JTqU88yn6kLK3bQ9vmaGRZ1NUxibTcdpo4hH91qIldLT+jrdmhrawRjYcRduYGO";
+ sout << "WXgjTbgKRTxnqrXwRD4Hl/B1EV6ggYC+jn3LQHaT6bYd1hORmtuLKy9duSHVCNBAZvnto27l+h6g";
+ sout << "VbUF8eZasmk+q8Fn83bx7C3eKoHjr6acEUyQxtWVCbmeaMd7h48Mt3Z3r8TyX3DkwQmpClciwpyC";
+ sout << "E+pbYEWMZXGOuXPmcHTM/Iky8jNSWyw2lLVQQUzPOJ0v0dtNipYRZqBQCDtSE0JuA3Jo8l00uox2";
+ sout << "bH11ErfGplsGZJejPGL8ba90e6xeLwH5oe/GduQ0/Xk4+faqBhy/7TFeexQcFDRCCTrC8+jATm82";
+ sout << "vHo+NWJjjDlEI4+F2FOhpRg7MtrrzNP/e+cD++wYeGjkRplbxd5PeyALnjZJ6kghJqFLL3NJ1E4Q";
+ sout << "gKmRErg1xWWQzyuDbbXPr5dwwRyZU0gkG0WTwyUy2dFV4KRyn2IbMH6STm+0af96YF0joZzkUroH";
+ sout << "ztMN8dWtmQESq6EYQfGlhQzNoBKLXjN3LK4TMWBE+1N5ilXkgv3cnN74RZHdLhEXRJnF29x/DmVQ";
+ sout << "qZQ4s31Vk0kqKdQ8tW0rs82+dMMtFv8+P2rYA1GZJQV4P5/TBU36BVetlN+swvULk4XpoqhTTMbx";
+ sout << "Oj9tONiyIiJitC3YiCU+G5uL0YETB8nSKrtHRiBD8k7nYj4fbUtSbu9+lKRsVK7kU41mKdBImON1";
+ sout << "6Qk0XqAx2DEK4w59khYMRRxOD4u2zZWDVp+Nl7Sd7ihas/vQx5yLXHKmIpjCK3SQYjJz09txIErQ";
+ sout << "0wJJZoSxH8efhGsTPuVrbQpGcHLD7bIkWf5kjR9MmOBCmUGgeeGOyi45x0k6Cx+z9oaaTXYcvRtY";
+ sout << "M+R8tW5gCLaOPjfbq4QjP6yfYogoaTiSEKOPcMgiOQKrXNiv2ahVBT/lvkm6Q8+IdesGWJtD6xqo";
+ sout << "+CC486Du6CFDzAHcnLMk5c3CqDfFGl5Yf68bV4aGm28BaM4vikeKRhm2tULeM7PipfQiI9R9Gy/L";
+ sout << "1yZB26qciwCalP4CA2NVjiJut7FZgTF2bO/g0qfvyKsAxMetRTmqALBJi8QvKqAE4i/8gRlTuwgV";
+ sout << "x6EGsUPCIcQmD8aJkZgy8+erSAY7MLcnUXu90AC37BLyaOt0tzJKfVRb6cP8wfZHqJneoGSNAA==";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'feats1.dat'
+ const std::string get_decoded_string_fhog_feats()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'fhog.feats' we want to decode and return.
+ sout << "AXAWQhjCEZzu/U+RFPgnRfCFsyRzQjyOA8TMshjEOL3FZhUZD4amYHfLuNN8NZrJyy2CdiXOWrFH";
+ sout << "dTTKsMQkSz9f2VGKE6GCsTcZ+fpbk+d7fBnS2DEUkw5ttiSxj/VsrigkeV0MEUR//EP3/w1uvJad";
+ sout << "96PFVeqVf6tEmcuuUbYzViC13lfnps7ftXmic5CwLZ97llqMYpLKgfEIXZpelB2al6PyVAg2FOfe";
+ sout << "2L/SzviQ001tYYgx+L2v057L/lJdx2+uOQ7tovbsY0zEBEXTr14ZQW5Wd2lWnj+CrBNQ/4wMQZIV";
+ sout << "86X5JV6nl/fxrM3eF5+U6U5cZoZFnn9vRONE0kf6/g6W4Z8qQNL2mJ/M8oKoLGtuaaEjymk0ENRM";
+ sout << "0M9GMLrO/qfcH/DHUb/HaK851L5sPuf150ecpIbPmQpxTOpI5XwmvwDAP9BCmLazQWQV85wJJFom";
+ sout << "LjT9dNi7eRsV0mNCZDwO9iwUTv6KfAR3Vn4t30X3n3+x+Yhnq5PU/4vu7GJpje25uxICm6+PC9bz";
+ sout << "QJC3wiw7jrlF8eRb2kZywIJHWtrN39R1tddENrGZkU8LlPTDcqTqfuwC1HXSt0GKlDRBW42DkSxm";
+ sout << "E7yKype2G4bgbSnuf/LKftuWlNXzMP3cDFdChtKJNOws6btgvS014C4UGWe3uNVp9SNAmAFyh+UE";
+ sout << "rRTl1w3RNom0yvlee9IP1sB8mOEZn5Rrzo2lCyTm6w49PlLfnS293FxvnpRSSlvqUt1lhzzEh7Wd";
+ sout << "YjK90oPWGqvNn/bP1vQW35KlVrc+JT9VlewcZRYJAq2OigVxa9Ao8Gs+fFyh8/Aym6Y3Z6+Y7Xna";
+ sout << "fsmYdGaUtfniJemtzHatTuhbuo979fqkIDQ6bhHlMN35IyzK26QKzGrMCaHenZEKck9qR8NTkhc0";
+ sout << "urO85952cv4aI/cJ5tz8S6f1v71F1gIz76zL0UNlkULQf3tqEleTqVF5Q+YKAtov0Tig9xiSuCZN";
+ sout << "btjVVpg06zlRqmnRqWpZU4W7uu19MKe6BGoZ08l5K/3UNgucyuUBTGtTGt35QaML+N4WLcTYj90J";
+ sout << "41Tlt+OD4C8nZ1ID982h7X+YxmnSdMNnaeM2Lc/h8twOwg11vHf6OSo6st4yjK201O8lH0Lemips";
+ sout << "LsO2qhAsF4AcWVG7HKUNh5jMr7TTQ/SPP2qiJ6eglJYLFAlwtCSXRSJFuK93Y3eUtzDpVDh44tDJ";
+ sout << "y+Bsa9oWJrBeBouo9DHG20N+wJB3rOVDprmq1ZGfhkSzqmVzPk6motDY/jkPGZ2E8/NIWpXpyU8z";
+ sout << "cUbc8Er2cAVshJ9uGCg0tUh6lGWsrWucpgCS5lI44PJkbSuyFZMbIZrgxrVmkgOa70pmmuHebs+c";
+ sout << "GW0FheFD0IHXVxaJtTuPeDuMML/YrAqdyzibareHbg2Hn4aS+qhRUcMyemOzrvjhGF23oSXbJqaO";
+ sout << "sJw/DWkt33eFNqWxofXw2pWMMuF8akESryBDyGEfk9nofHoJhTciXGNkuxIiSZtVYsVnKNU9C4ei";
+ sout << "31HWlbHjMtG9RD3zqkIXwerCkhElWfxG2M9ja1S7M4+0VrS9nT2ngc/n/KZDpinuB3GIOnnaqiqQ";
+ sout << "8ASsOEl9/Ni9Lflomns/CdxWns3OlcU8KVhWHYz5hqV+MI6SQLlS9j39WFKd1IPaer4y1fd99x44";
+ sout << "jkyP4ekjoVVfVxpJlb4favfwI1AnFD2K2TaUeULaALTuBwNT5DnRcLNnwqD+6r33rEv94Nk+2+bB";
+ sout << "0QPLkojfPlDJocwcGon+z2EHQO4t+RPAafjQb42dNCymI/bIdgwL64vldhl9KfZtXhE4llYhYuLf";
+ sout << "xliN92ELGSt8o5IdAsoOoCPdqQh5NujdDs3p8kVSETq1HLilGRnuxyVwrTqJEUC4G5ntPfqXr1Fp";
+ sout << "revo1FOr4SRa8+c2GgA7K8/fvXwN59GONFMKxt+sI/xko8hbOQwOu1VEQ2Ak1aS0cc5MoUrhUFhF";
+ sout << "gCTqGd+9bWwg95ELl944dD7MIauKl1wHy5iI7u7EDlhvlGhmtU+6lzCmBiDbbPnoki+yZLc0V0UL";
+ sout << "jvaYU1WlKZhjWcA7fHkUyGchIe+KJE8DcW+huCO5iz6gPWwy3ZURQEW+wYPD4Sp6szOTOPsNKcN/";
+ sout << "j9PxKGDbNO6/Rou+TEfznVuu4ltLKZSDfYMK9g37+XjMLHTU5jCoPm9KJDjFvCTRAcmRoQfwuXyY";
+ sout << "o7w4QwcevrjFdb3/IYMrygb57S0iMkFJPUUiCF/bOfQA8tpLePYYtg2ILGGuH2UFwOLszxguBLLD";
+ sout << "ziSVWU+xmCi46kKVuNE9gyeT2OCPtn/U+qEu2B89UkbynI5v/FVpJhJf6MjLc1jfDrEi5NflvvCQ";
+ sout << "l2QLJGjtfDRJgcXFuuNzWBMiVglMOhT4n3bta7tV2KraK7Yc3Pc0GIZv/zVHf3BqeDEikXdw73tt";
+ sout << "aomM2RQstiy71sMmGkmCvUnEbgrY8O60g5nCSmMZIFbbLit9dLyBjHFUELrLxXup7wmkxu+ZVEzT";
+ sout << "FxshL754iYXXkXTqVGirp3NNNhGKPGc4g77Yne+nxpkZ4MwOi3wQ7YqPihwIkIdYewBMiQEJ4Y8W";
+ sout << "0+Os7iD8OYrccbHKqvKMTE84QOKGZSsGIaCD+iIvv9F9/EIB2ZDv+2aEs/3ix85vtg8L2f6WmGdq";
+ sout << "fOdoKVuU2pPIkzlyTNQAwai3NsjcnI++lEpVC8s0K7fpIN8uWDLRnGGuq/G2gFQEoqN8eP0E944k";
+ sout << "l/YTW8+baMZVp/wQNA4mo3v2UvDdHrDcZmIvVuwEaAUW4dwylXMazecCG1SMkusYSXGoorB615oF";
+ sout << "DaqndLnQSfyJrsXdBdZDAPmsssTuOvCjrjTPnb36+WebHGuLUNYZ1kqjhZt8hnxTFuYN0sTWb+UU";
+ sout << "2tL72LNTK66l8LuuQKUMimV2uHT7Dsv4VX6XE+YXczrC0HycSaVmtshxRh99fnNTEtDKo2bXbSTt";
+ sout << "s57BqGWi3/orxqSXecUPFYvQBjrIfDrinany5uht/8FK5JH+c4PMTsbiEeQ95RX7eOaBo6IoF7PB";
+ sout << "zaXhJH5TW/qwdO6K/Caqvjp+no08tUTdn/hRdGMyQ8cIYXsMaiQKbkpXlGnhoBK34XA12T6pXa+E";
+ sout << "QocfgTw773eQRFWN6vmhvuv8Pd3KPJAJO80slizTFSOvxVO68aM7gZdnDFTgfibe/v+2N1xIUq12";
+ sout << "B+YWn9yGP232QOnNq0nuAvFLhuzlau3U+qR2n8DThKWTboF02vsqThaQzF+0EPFk/3we6AeAiatk";
+ sout << "dcvXEbGk/TkGI1V5ICcpGS/fvivZlqYhAIL+yi5/5M3wPX14KwriXpFVMGKozUYaW05+27adupOM";
+ sout << "p4/0EvfeM8T2m+MQ3GcPLA8njXEDbLLWnoZ+YMC3l2OVRMV/yFXkZvQd6tAQUymv1xB03lNv1M1K";
+ sout << "tPE1Ps7ucMH3cOjff0fZOEYabEl81VbmYUCYfntdWlApBLrs3gBWiT0uLoiV3cJkq2VWtgpeyAcJ";
+ sout << "PiZ4L7AblENmUS9gr/7gYdn3uridNqfoos0uvUCFrIS4a7siub0FpCMwiwSiyZwtUoD5vcq3Khza";
+ sout << "DVGJoijIBo/yEgUTho23FJqMaOYyRnVen4i8GH1H7PUhJe7KThuQYk4UQP+XO1qdLITUwBlbNvks";
+ sout << "ciB3IIN6QKQTcoDXEEQaMcPYRNhaaGYFDeSZ4yIRhLV5JyPhOiLFj5EOzrC2B14Op4lOkerAY2J5";
+ sout << "cx0CN9xEUrm80GJGtKudSd0JKscXIDTBj9lxngSScCmKQRn4AWJ/acRm/fyc5Gpg5PLx+o0jCI97";
+ sout << "hm6qOSqslV4GS3BozqP1x18yqrC++IJvOISjjfSvSAkW2s+qv4ba9gfNYIhsJgAan1vaAgSPDXOD";
+ sout << "hf9RJHBE7Xi86Ux4uK/o/0GK3R4QsKa1/t6qij0XAlc6lmt6MXbSr/Tnjs4ykAbSjzmiwON9Jnzo";
+ sout << "KYQiY46ULY+o+UjbHTMuxkTJQjCKtyertjpISD1yNYBxItA703l4ZLK0iklv0ZrFMyov8y4ySVmF";
+ sout << "Tj/eFWy/PpTEQdyzGXrotmYbb+V+BG5e04bq40FsUhhALgSkcGEYoQtxLCZzkbyWQmEN/uXC9Gdk";
+ sout << "wG6Iln2vWqzZSRMeGZ61VMm+dzr5CN2iHtFcNQnjwWHgr8C726YO5j5eWLvHqLouU8ufiojzvsvI";
+ sout << "ycQ9aUfkcr3AXu8hv0+SOUK8mT5JdQ5aPXc9WOe4c6mdgfOK9Jq2ZJCLgQvj2swIoGQ4OVXn2D4t";
+ sout << "MNaKJu0/5ujgOg/634gfxJbicVJLzn30TgWYXX6Ixj/JQW7yxM2iYyHyOl+/SltruQS+NnF+llzd";
+ sout << "rYuXYejtciq7Sf+DFNOJPSaTJuI12jSl4yH4fOMMkkxWMM5QkFzgWGK7A90BJFo4Uhy05TELqU8J";
+ sout << "FtUWdrngONpIU6haQcDpoYtXVQ8h06yZYJnVQBToS4szMcsPPUVYxITcGnbT470DR5+Rrsm4MSkO";
+ sout << "ZXmf4sC2G/k5at6a8o2OKsohg34bNzdo+R6rpJLcMLmUogDdHj7uNjrvMXgZgN2VS33jpsKaVuww";
+ sout << "0fm1I1pD6ltIfO+iF5oEOQz6Ml8TSxcGei4xi9Si7g4KGTZ6+KhS/KcdGQv7HsGH1+auYumQvKIJ";
+ sout << "mWY1hPH9tLSAB5t6vh6YUg0Fx9G8Wf5Twz8JXsoyRbOs2AAvXcBQ5EPNbNiKz71rzPb0s4Kd3TKJ";
+ sout << "cNZexkD8z0J8U/KVzDHA4kyJU9tKB2ZArGPkIYAWw+u9d9VGdxXgst9WtboxuCOy0+y0XiXez1nq";
+ sout << "8Tib6FgDNCMKD4uk1GvVs697TYCphk9MlHPUevFlgBJuVI2uOjsnGjBtzQOeuWHyXoz8xQhyLtI6";
+ sout << "MnW6c6lCs8REqpAWwuIPF6YLzAZd4uhpOyKFTWI5jus7I2Rkr7RmFDcOCXcnHw7M60Bvcgsa5xy7";
+ sout << "AoMab6/pVJr6EjwK2JEmkLaxPUU/F0WqXpI8roFPbIZ0sfuUzZ7tZmkZtelboyTtuEZTxbKagOWR";
+ sout << "78qwMM9feTEwicGFlvyiYdUGaIwiIckil3oQO9w6bQAaPnygDcykVMFK1fZaZztYQ8AKiEjyr/V5";
+ sout << "dvc04CEShL8uRKDZNY8Y5cDGVHOSR2g/u0t3PDuzMCfmQeKNJQgc0uF3ozXP4xvTvopiK58Y3656";
+ sout << "m2ZUfjDIf/g9gRXmrmte452CbaU4HQzlIblKaEJr153rXTQbZPbSHyHOHWRuczQAtnyP6k8YSC+3";
+ sout << "zqBtSIvq637hKi+7Ov8NgiYhw78ehwHiPtenLDlB/YMCwqqPNmo+8eYGmtOoRgaQecIoYHYWfaUE";
+ sout << "NMtwvnfU5g3JS0j6VZloZxGNmrtuDqWoXclUftoQdsDlE//Q/5+KHzyZjf60WrXx1Ix35UmF9IEI";
+ sout << "jEvtLp8KOoWs077NCkXs0HVwuKxbpZx0v3qVb7HwsgcaoypbjhWaMGYflEKvEbJt+TD4MN8kXDEE";
+ sout << "VHFdCSOzUplHRdcy4aOkQdzfEYvNTgaiTSO2CautGYgS2m+l6Cd8B4K5PZs99xYFa7t80L1d2Zpe";
+ sout << "M9rYCt6RKakTTFDSR94nxxzdyfbA9sVYu6MCD1G0lN+zrEisA6hjqSAqUXsooaW4WTOd3HoNkZeS";
+ sout << "tGviSThwRe0awN4pH5dXfHtxaRBkzOBVw12FB6urObgv+3jcnTzRZWvF14ioEmMuKkHb3Ienbv83";
+ sout << "71BeuTrUarJazVmIzbH4ulyWwLxEHeKL0r4PIEfbUg7tiU44lMnfxmrFFR6FiwuBxrUvyv/yEmiP";
+ sout << "AbMnRjX+4MVrIHr001qxVFOaeK5FehfvmWotuUW63TvubKCRp++5uQDUh/LeMp5ZSX/RRVpEKEwA";
+ sout << "It9wUHj/cafFqSwt603pOOtAC+xL0ozsVF1kYyl9vBEow6mBe66WBwekd+DjlzLbehk5oIXSaYsp";
+ sout << "zu0iBnukS7YoO/2Ho5JMdkJuHf5AtuC1bDt51FL9McuIHboobI3/K0YrpwPmFORwSUSroXle6XK8";
+ sout << "LeX4Fcp6YaicZoFYpLVbhVvrJSW3F4zBERbSqBrHBMxoXMblajhf58RcPKwZPvPnSL+yB5V0VP5X";
+ sout << "RJtdo0ir42WND1VCIfVqCCrSg/m+/R2sffd/CzqQ/JuJnwPtKrAvuaZ8zbmq9UkK0WAWY9Wql+gy";
+ sout << "AYQNgM6Nd9TNJ7LEyEJQl3nK2qjg67rBCizIdwRcPFSWoWE9DjVz5eFPIJjPG//dpt296BsBeW7U";
+ sout << "NhV2Ig9EstFK3+/GC3annnXsT7OQt7QCnx8BvzbVHiFU0n0yikhA1uU9iYm5qsVwdJ23NWimhTeo";
+ sout << "XOWG/MVCrPHpV2qs/4PljiPW2eVdzodj+nfDPVwkHwmFm5Y6TGDRBfJWd+ZiXMkrDa2CEMrMvzEL";
+ sout << "/DymDMQfMI9HgMiLWmiXS4DjcRL1Fp7DTHcQa9swLcZwbyE8r14L+5xXzDySF/EKJ9LwmldUaN+t";
+ sout << "qjmQ7DecED+MkTHMYXnID/Gl3a1/wnrfxa9IuRAwHiIhuwb8siPJT1S2mncAqk7YwUyaY0hl6TB1";
+ sout << "GJqoaPTaeFqzTD1zuz5N3cFxx1O0R7OBzHuBtV/JXrZlyzNKZhUaopWCyQ64+RGa/K/lQcyJNVo9";
+ sout << "lErihKgf/LNzd7f94T3CmYMRUJZanOLNUWcOg2iJLGR3hy1pnlmc34IgQ5SHZisUBy2jsdK0xoKA";
+ sout << "Kb/cPiaZj6ab/4sq+Owh5I66r7FjACv3uILtt69Fz1o4yaOb8z1ZSvFei4CPrikpxYXltEj+aPZq";
+ sout << "pAyL3+qrlJ7eOYE2svEpEAiYTztUAn9/ukCZZ71IafGHnhPggc+eizHPuoqfdUa1NWeM7H/XcFHH";
+ sout << "b5PQ2mQPCY1gD4SrBqPS7I1QvfMuOSRba9YFbJAecSC9bPHlQQ+c/rma+R3yhyLyXN2j2xzHpgJr";
+ sout << "oT2cEn9yT2fHRiZIWqMAJa0KRJgRN0hLjhGQ1VKN4WZfKy8uyqCrAbzBqR0eYcDjkpvD/syBg81K";
+ sout << "8acv+5OjBrHgCofewj2DFs0lC3mMlo8qe+GNjxu/CZufpnNabIY4ggwBxdMWZvZQ7j27VwMmvkdd";
+ sout << "Uei0foug3YA/Gy/XUTRLhuyYKy9dqdv6VTSiek0aFQyM4kz4KqKlAbGixu17SFgvZ33fP6ZMZ5Pd";
+ sout << "eWC+Z1vRafLRpsABf1DJujXUEUZ8HJfWBuuaMkJkxFApcPwctu4SMpZDjnoc/7gblzc0yLr8BRxD";
+ sout << "gygNRNu4uVAT3sbaRzYOvF3tq7wr+R7qS2YmPEzhoZyfubEHdV48wmE3XD/RnZJ8maanzDjEH/Q9";
+ sout << "yX/a34y6YSlrtNim3R8pI/AddLi86cAcEKfK3V9QXCGFqO7GfQuyZHO75grKpL+6MwRPUWigaLGN";
+ sout << "9JfWrc5tpUu8NPY0ACmztq5p8iNqylVgIYOC9LRIl6TKJQXPSY1k73NpzNNzOJhVCCLY2IaCMUtY";
+ sout << "pbxZs+VLufZmNFhq1D5qxUDfKII7x9ocFYqtwLnjZztYT1HhDTcwmB+5uQWHoXKRvsTgvSfR1l33";
+ sout << "w4mqzDAI4ykfuNbLmymuKaVV2ST6W7pI6xfZd/YD1em6OQYF+F44tj2G846Ry1IsdVK8AiprcFHA";
+ sout << "QFxuwxcY9eUgjSvhbK4BKkQgFSzx7yDZTtDxXSWrGsPoHUCh0GKU757B4ubLvDV197o/No9EKfGh";
+ sout << "3tlmEwvvwQd7yTgwdbksgVieGZBJqLK5eRe3CqYXpHryPcxydrO+2LPpzUiiHPY5FDRZjnYY+as0";
+ sout << "IC4dtlX5BicqVB2gbHiKHbjLf0pob27d/WqQKKfA/7h2wY/jYyckEiX8g9M6I5QeABzABxyyAMlx";
+ sout << "zoi3bd/RD35ijUysmIl/+qi3GHaYKK9Bfu1SRb9oPgmFYKKKRrYxm/cypmJXp+GUjlNokWN1u7OM";
+ sout << "Nm6oqRRuqYWiCwZge4HHVQkQs6BuH/Nqvd3Bqkt9U1eH4TnkS5MhnYVdHt0hxmG6Py5A446SERn1";
+ sout << "gJRsUDXk/kRkird01o1UqCrlhwX9WG1cjY2I9nFsokudgnYryxn+d+hVdM4E4MO5ZHmOXicEn+hZ";
+ sout << "N5eyfU7B75rBT/yZzzot1k+B07BE1x8K7N+S5JX07utAi8/htK/a4vxKhJiyx7p8etztBI06LKss";
+ sout << "grLKdJtqZvX3kwFEIXqpJn5W2bijJNeQYnJxfFY+5D/k5POGuBYjf9lw7ilnIkbEDkaMWf9Mrt3W";
+ sout << "A30zlSEMksIByxqL5/VFx7oM1oSx872AYwXDNNnfITgNwKBwniRHuU68SjWBO37CYYmDhcB7Ug/M";
+ sout << "FMX7oBgPrld/Lg/ut/xbWwFOiM1M6L0TmT5HX6RcFSdKg3Sda6adAkSK3Ux2HTZAUVaK8zG2Mm1e";
+ sout << "W+/4SSqK29MAZUBK+oEPrNB7An6NgWZ0TRu8sGeMcZCm2Zb+3+ZVUbsTFoG5pFhzzvMGr9fAsh3Z";
+ sout << "4Ngvc76mkiqT7xDZw72BUnrPz+eO+RGqMG+oGWJlXd5PYD4XIkW25kBfOr+iK/gCFUsfZbFoHEFa";
+ sout << "M9EFExjXiZYOz4iuSZnpeChRQ5wbl/56iTGSMHpB3KKU9Rfyv4dIDGS0KmnSH7Q7mdn2lXerjDmF";
+ sout << "zlc7IbX35O0kHeSXaH08ZFf9vBweKQvEW6Qxs59FWPuS47FpXRAPFClwYskLxByN2ux9kxHprAFr";
+ sout << "zuNKRyilr/NlCEJn5SiYU2/fAif/YrNNiyxXx7sWwQW2mf9Emqzsrkb+eCqAPs1NmwuHO8JXIyKO";
+ sout << "0EbIUaVuENKa+DLtcrfI9HlxhrF8vd8m8s4ZeBHWr3jkbVdcjX9mmtcSrHyHXcWVImc8CJOiR7jw";
+ sout << "0HTAydarj2G229/7kLX6RncrRqY6/Z2e0YEbfTt8RDnwriUmKXuf7VUMljP+tWx8aXMlbm47WMaY";
+ sout << "nnjZ4wE7UTgrYUce7ehuGDBEM4VaKYrp4n782gXFdo9VhUZ7JEaveARi8Di1SI5MuTQ8N2hUfPKn";
+ sout << "JbK8mEjSmcN1sOZBOXxxWX+e9RRsO5t5ujCSy+UBr4gaqMHAlwxtBmif+kl7s9o+UjHOlWLn7V74";
+ sout << "PiLxVUzCTHz5A0rX7MyGXMBai8BT5XjmazTZz8YPIiq/ZmnyULon+uTrmBdivNEjDq4M476YfAma";
+ sout << "rcqxp/picZEanq8yctrujPHilXH1WuXhkPM+gn9Gkjp/sGfA13JiFeXZO9GJHkqLwBKApqS1HJIf";
+ sout << "bhomnqcdp6+hM/IEaNS3dVZ1aTSefIM/OTR2fNVbmzwfENzVke3dCJvw5B8zTsgEXeKuRE58pYaQ";
+ sout << "H+ffv486NoO8gXKrUF47ptIj/Tt5apc5Pt1AVFsuaxvry3UrUmY7MLbfM4xB29ah1PY9iYx/OssX";
+ sout << "DGvnDskGHiQJlz1s3saJl9qm3BZr3//6D1/CgGvXw0DffJYL9yIqlzoBRKAue/lQbWagNArmsccI";
+ sout << "WxVk2TqYgTHwhl40fWSGIuY1kfj6FEAUxBBxGul8y9Cv3e/hMnE0gDQz2tZs7EGqP8WqKPF4BpDh";
+ sout << "Ep+6vvj67y2Hf36GALRYNLlhCB5+HygzOW4jwtQvCHxbmtPWvQkRQ8iQ7XlZH0OOATz1FsccBZXr";
+ sout << "3+O26cf7zcoZIE28MIQHIJqsDFHCJVr8JVcYITcv46R1z9ZgQQ+z7KK0M6FY6SOgCyu5kyQR6YJd";
+ sout << "HEYkNp9J4N21iRr08DUYycJDtrf7xoyYfj2L5QjpPVEKrEhIkjb1kr8uZp/KfCjCkedPBrMsPuOJ";
+ sout << "28Acpne2exkkKaunrJZr64Axfgl5t0OIBP79Cqy8PRnMYQTtqHf/pxaHNyrYaXO9vjtTVoV++kaM";
+ sout << "svy9Ol/R4LxEXrgtlSYhKF4o6iCJUSiLhE6j/xzyOtRrCAHZ56WCJ7YTm0oa22TtH0DvoFMY11Tr";
+ sout << "SZ04ig5Tl8At1jXKymUSnK7EXANVHZmZ+01xTE4efnFIf33N4uWK+c/hEqmS6KCVjuHT9FwTKEIm";
+ sout << "4cKum8uhL11rodikW09dYfIyQV9yO0k6EJpeUSQMhPBqbgTWHnVQoHoot+c1uBoOdK/+bRuz5vip";
+ sout << "l6+0nmpZZoO+OjdEap1pQqpcTEhmfBuUGXCibggZhHEvHvFGQo5an4N48OQA2B8CccDHMJIDP9+j";
+ sout << "0JfmziBnF+ZOLfKLwuuE4uZg87iSWFkwSynsWwoUQ1Cy3u/URW620WLmkx0GDoGPkcsxJ0LVu9dh";
+ sout << "OrWWaFesEANPRMCKuuU55hs913KzoOKdgZPzM8dheJZaZB15wi+u/RTm+obSWZVwibTDyLPQ55mz";
+ sout << "FSv7Lyp1EDFvxyel+7osJa5ifhLrU5f6CAcKwS5t2IwaZaBxrVaFgX5lQmifY1Gd2new1mkfWYmb";
+ sout << "n4AaURVZOBC4U1Dx65ch0PNeEYxk0DLAGOsvdBDbWbFMNc0LiGEF6GiCMBYVsw/cYnjY07cEZg5N";
+ sout << "M9RxGfLfVlyy4MW9ek5ov4+NVLV+vaosZvA9gP92vaiS7jBj8qCb2uYIK1mfrjHcOUFqcxgzltBR";
+ sout << "eSU3ewoVRJIaVreWX4RSXTomL1GOyfcFQ7gZghSJLKlwgkK6+yvqig0jyuvmiRFJGDYOxQtDykwM";
+ sout << "EKOOZrckRdktXs6aFQOla+IRiN3XVUfY2wvx3egfOYPKrJS2HBEdXeIelB7LK6vRx8nwuFAAwZWQ";
+ sout << "iB4OvgM8U9N2H1wa0xXWc1897unEm1KxAP1iS44BmZ0PPASPa1RrltkwWMwRtMp9fD08mwLdGe88";
+ sout << "fsGIrnwHA0HIShoZaBmCSvX0yfaJ34nchnMukP0B/8v7f2j0t1F6hr5qJNSV3cTNcc2QToBy03ro";
+ sout << "GphkM0UhwwoYTlFppF/8LV4QmtsNK9wuziTmv8ghXUgvFRTtVcBMlHY4SFcRKoagFF+B1UfCuVZt";
+ sout << "G8fNilXM8zc2/eP3g5FTU3YXRgw2CAheUNiekne53EE4DmDJ1f6n4OyjZFP8PZ85Nzkkco9FW/8/";
+ sout << "31JIClFqSE1VGbDXleZMOrdfoknF55krQB7v6Wsu82gzQU2AvvhbuFlPodDKH1xUuUT7gERKv4ka";
+ sout << "fdS1xf/PRafedvPX7k8fFZQerqvvUlgO6PaEAxK5MqZqHiUgUh9A/pqBZNBl1kQLP9+G70i1CY9x";
+ sout << "tTETsJJTgYz/HP6yXsqeFm52yO24myKHMURYBmOZU6AFyqFCsOdJG/GA5otaO9MG0A3hPdC3Py+2";
+ sout << "GWbnl11yPDVImktL+LYbx2oolBWZrelLRuKAtDp4p/Svt5R6fOvYM9XxZnnpR/MNaTt7I8iEZSQe";
+ sout << "w57IL33ZfHgKlxEr/ouJgT3vlxqXsuXnP49ytEVKGja0JAOzlShLYqB3GIY9Gb3EtN0h/id1jqQm";
+ sout << "QwR8y5q54W8pdYflhgi92YWYroUUIFRxheAgPwUSqrOUNiN6xpSwr2usNY1zvGGsRqFKuhKgh7P7";
+ sout << "cvGc2sOj3izPgl4NlR2DaoFTbXd6uDM3IrYGSCFJdbMlonX5cvO91ySJpKwPOnqjAbzBjnZCfepb";
+ sout << "4px8fSH5I6LJVU1R+sGRCoewaHTFlsnaCQrsy9BTGMIWwAKCAYCbWN0T4ItZaXhJWarghYGsT57P";
+ sout << "MagSlMpKeiToHWnWhPhtxkhm1ZVRuYekcpwrlWwsHBV6O5pEML3wmWZDWJNZWh/GkmhPhf0aF78F";
+ sout << "2lOVKBWLYq+4Xt3lVNvqCr7m2rQNH6KzZUNfeoIJH48SgirJQiNNE2iQOsReTQTbCW87NCN4GKGh";
+ sout << "Vf5A2JU03N+5fT+dorN/LTQmeKddK0MR2nshO1m0kZSQ9TDUE6Da7ITtIjGpKK1QqohIx9BEMoML";
+ sout << "t3BcLTNkK1SaaYRE9Fm8AZXr4z9AILXUKktv5bytIRBZncs8078FdpF+O2JWEzELgG2s/FTHTyjU";
+ sout << "NU3A5q6+8LoeSXuoqOZz2QwEMhKwkz7AlujJU/CJ3+uZBAUBythODaVBlaZM6/f8dSY3489Xiu9z";
+ sout << "L917CSsYpq4JQWq7I7pOkPjy0t7Y7QmKPITQv4QQmF3P6SJXiainjWDQlZx59RTzg2Z2MDZ0dcWx";
+ sout << "f7f44IkngOVEUHi3iwrSygMTySBYdDxei/kBt7oXAAkOMLucZ24VE26nLD1hMAwRz83ENc0sOZAz";
+ sout << "F7He/e0H2I53NAYlk0s55wntUcdp3sHh3UOcGyBGcRUipg6NWy/LrWzxWqJdo1DsBpV4iazYLRfB";
+ sout << "JdKobsmPGmWSyABV8tea/IuVgqUm5RrWfBUa6Kw2TqVuos2PsGqsRi4cHKl3XQ0GJjbV7qV7Nacn";
+ sout << "mRVqIAetzUUZkuyp6Q8OMLX36zwwrlP0rPJaqk24VBEnx2FKjaR/LkP5lUFenOHJuPXSh89pYWA7";
+ sout << "7/y1i2ejWuMrpElkJ7qfpTGD/A5ZkNWCyla2VXOXUVjK2t+cBYByjEwlMCwr+tXUXQYVMPf+UzzT";
+ sout << "EVv45u14EhFg5XOu7urPZWyO4EbejgEvyyx0c6Zgt7RaQgXn+akwMHI3oDn2NcZYGo8Vwg/fSs6j";
+ sout << "Ggzyse3ShPpUr6qb9TT3Vo6hXegWwd6tDPsqDlc62JhQ0MYdw2A1x8aGK1iUCz4pqsWmXWhGPO1g";
+ sout << "rXyqBaIrVHDMim3cZO2LY/TOwIJZGuHNvVnQQ0TDYAQEgyej9mVLuWaFuCE/JZlw/8U2VngPVq0w";
+ sout << "EePssUQnewMHYTfceXOETEBkU0xl4WLdwaJbvIXG+pPcVzYW8z/D3yh2LU7KHbklffbjWhYyAm3b";
+ sout << "nTTR+YTZoF5PwWA9DmsxIbLQJn3Ejss6pOj1YSqq1cD2r1+TZjWefNmH/nncwjU0T6e/iBxkgQLc";
+ sout << "NXouKJEemknL/HOvd5sUS6YYbIGg7Pa3ur3Qn0quKT8QSHRPTxZeTP47rSp+Koibf/XfZOdG5RzB";
+ sout << "U2Kbz2vi24JkfzbNCG3tjNvzPJVcZrMde1TNVNQVFbXCzMZgO0Za7o3IRyxy05rmieBcGryGX1ln";
+ sout << "hnhwSzxSSxnuJ3szdlfw1j68i8LsX+iaZHonWIw21afDPwXaoflD4cZIZI2uPLAKeBoOYMxKyFGj";
+ sout << "2KhIVlr+poDcu9gZBMF3CwwxSRZpwVhpUllBfOJDJTLbM3UOyNRMs/U2T6TdxH1fRbgeQcfQ4CqU";
+ sout << "D196crANUlHv6VL0bU8CFS5f85YwKO4JliKHZhvQRDtcBrwKIXttWPt1f3OONAscmsl+JtVgVt+r";
+ sout << "h1R+X0b/puYAa4tqBvUBiiokN21cQR40Pp5PPLMszGskImO0XM6Fx9spo80xxDLhOXZsV4rJKs3q";
+ sout << "lub2BoFFGa/nbd88uBheoBR8lh5d3sWciz8Y6eMMlEASpLmXFg/nqq1jzTlC7lGmAhyqSTAL2dHJ";
+ sout << "+8ACp+IgMI8v7DR1TEp0qgwrVC7B6+8bozJlpH73HdqQYkyjAnVcOBTn6KO1pjAJ+YcXqe2ioiBt";
+ sout << "OMAlNQVAJZgxpEnwwd16yXDmK+Fp7v8aGEx1EECVaQYW7ZVvKRC9249ioFaEgFjpo+8veoWFd9G3";
+ sout << "1E4aBC8rOXrrsI6U3QqWbYlusqvogtKGwT2pMYSidnPneM9iaJ5ixPSlB7VPp4MwdZvPIpOOR8Hq";
+ sout << "cFqQfZAa7sDq5idYKPUrRo5XD6szBNbb9Oob6y3G9RQndEEt2363luFr6Nv80r8yuyaUUlRcmPmU";
+ sout << "/VCExotSxcx6B4uWyd6UoA1wZv1hY+OCUL0ahArlLzkR2ZxowfeDCn5eoawdQnazyx9wSAEmqGTT";
+ sout << "lrT+MyINZeyxp9DTtvjFwVw1aDVT87PF7E4Yw2H5V/55elbLzn+Rlr4AgU7W+RnuwOk52LCKrSud";
+ sout << "JTAq/vix0svgRHAs3E8wsLzBsFXc9SZ6/AWptBKuix0lkoDObM8rLJMjxpQPmIyVvB3jWXITDn+n";
+ sout << "8ou5GgmZUDeGu3ZiOWbtPhO90akFKl1XDQJ+k9DGrlQd0dbsDa2lTgPbL+3wOD9fdjFzqfmGA2vI";
+ sout << "kg75VqCCEOUXbQ8N2U2IALiOEuYblJk7WVsbmOwmEw7T57QVJvivVJ9Z36TJeWfpzIiHCeReso1y";
+ sout << "3RGCo1qlsgfwtz5e3/ycu5aEq+Pg1W4EtSpeuIEZyH7zQaUILmAFP23JDmHyZNh9ewxSRfZGETHg";
+ sout << "KKN32MMx6taVzf/8+RQhxI3JJ+PSk0vrvUEX4L/2Bri8meJbN5UtWuRN5gha/O8jPDixa4XrMAiq";
+ sout << "etOumapH/QhEJBy5NHmcjLH7XpZ72qxTIL6VS6m2GjFUyekOdKZOHDyEKA0FR6wgEnoki7gS0L6N";
+ sout << "5plyHCOmd1aBWEXf5+P8EJeh1nmu6AXtDful0kn8G9nNnWrbC+iIj2QQ+XZPxdZIGuJKd6MrXf0y";
+ sout << "zW5dznFYvB8R+LTy2SW4WFvMWzJAlggi1N7w25/rvtnt57E+I5TimCjAKJ5Vcjj/R0DOqX4BNnOK";
+ sout << "MqeMDogP+DE9NesTswgfFngZBjomZsx8f2Wdzzi/UW0xBZa3yPk+CV+wwTlWNxgBKFCYFC8GlJ41";
+ sout << "MQt+TPDsDZJuBdbexuS/PA/zzOE/wZPVXgzLZFmTKsZAfz9894HEHalRlKLgTlvgW65XDihdoh71";
+ sout << "HDwdA9Knb9r2qH0dwsOTpoU0uABJkND+V1Ezr3oi35dJ2zw2gR0omEnVXZM9dW8XIp8ln8zegt+S";
+ sout << "dyMbNDzX9RClWSIVIGuRYGCahBqXMCJG/AAKvkXM87mZiQsIz6uLvJpkeGiG1ah7kTSjVFIKSYES";
+ sout << "73oz5l7AIAIReUzdvMLk5ZbmqdW4JHBR5XBA3rTpAyNEunRi2Ddy1eBt4i8I7GlXaaZ7sVS028ze";
+ sout << "VkY4WR/6FJKO8ccbofsJb8BiM8UZdPmkRdEKGgFv13dkq6inmo3S52P5S50mYapa1YKvWCvMHaov";
+ sout << "z8BOe6WqptQRGc+vZ4v1vgq40yaWBa9pSTyvntLUKCkQX0qi3ifKhRykXP6SBylckIHs8DfuJqXP";
+ sout << "X06djSx/F7IyvBQg90SLa1h5hYRTAchYX1ZgvG7LlSvPp7i+sWCx5D7KpTbF6O7AU8kMPpaRm2wE";
+ sout << "RvZ4DCgXdh9Lgw69wRlMfWJEJcV3mOIGDRoBZToyJqgHMDJigCet6NIsD2xvvza5JWPf3DURWRHz";
+ sout << "wdVqLXlUivD6/9r290ZcIbdWFMbz2aY9x/ojLrJmAGX/kySItIXsJlDbcvquJWNc6UYrpxurQEku";
+ sout << "ejm7E6HjXUPmi9gh2kRkw29A5xIFaugoph9dZSwyCEx2BbqY21hwQ5elfdcvdJD/fe7iiWmfrtxQ";
+ sout << "BqVebUOrY5+/vEvMf7EupYK8cxtCb3mvViCR0rGokTwuw7NVuMH6DEJ/zXB7BO/2bPXnr48Q2pmM";
+ sout << "pThaXSCJ5Ta1SZqGZRG5pBsUWg8MCQBc/KmDWv5csQlqDJOLvEULRsKdxxcm2wBthRXx97JVHMwe";
+ sout << "Tlb1TkjoSIQonMsvU+dRJCW3qhgbR4i0t7wGfbg9YdXG8LiKJHvkpu/IPKHZtaMxOp3O6kl7Lcb+";
+ sout << "Zr412Aanu8BN5GP+rW8/C+TjEBG/WeR23iZr6SByC7TCzZwJO25J6mtC1nFxdAUizSmxUfwDwvdE";
+ sout << "5WyGMq8TTIHZ9KvKMw/jODKXcviOmLHY9CsPtYXbChnF/fWgQx/ykshrLmtSqFEaOt4YCiPFKQHh";
+ sout << "/IjsYqcs0UQeGTk/6tnp8Cewe8A1DAaBEI1RTllobQKLXEUBWAV0VcrVXILhemvApUW0uqu6dSqg";
+ sout << "cfv9uvu1BblNEfNmfTcUssCnDQ5c5vFjEB1KESkrBTL+p6bEn2b1bbxQrhiqnVO6mi9anbtBgBU4";
+ sout << "lTjSG4KMnsD63xnrLapoU7ReEZxGjsQgm1Af8/lewJajhNOZi3FmDgkb8Lhq2rz8OYy6pwXCEM07";
+ sout << "JwMzOWFBZDUA";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'feats2.dat'
+ const std::string get_decoded_string_fhog_grayscale()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'fhog.feats' we want to decode and return.
+ sout << "AXE4jk6QRzUCNtyVtAwaCkqQk/DMJKm1t48e6FXsZJ/Zfw0Utm0AVwNlJU7O2+XVsftV/yE3zO4S";
+ sout << "YG9DY33gIQWV6sw7AGva02FE7zlkRbW3IOyZeG5LYs2r4vGYmZvZuYQJ8CVmkJpGrYioIuqWLyoD";
+ sout << "IfAFmt0z7HREwTsGxP9BG6UIXb95jQCGocuoO+MxQNpq3qtMAr+C2xnN3Na+ITiKYUX+zEP+FrWJ";
+ sout << "uqsYqhyN4H+1rlYaLhrj0nhUs4+Zp+fn3LZecDsZGeq6KDEIM68rOZAY8WWA/o4x30cQ0P299z2m";
+ sout << "7Pl1vRxpN3MdgzkS2zlOpGnrexfA3TK07nFcTK4Lc97t/75JULM85uEo6yYUBjyeY7MPYTHaM0tH";
+ sout << "+TGdAqQBf6TbnYya1MK0BM0nVLp4TkMeRZj49erCtZIVaFWOYmufs3LywApX8AQZAsBhU0QA5cQu";
+ sout << "G6HKcdTiqxUxbjOIueAxWBbDbGIwUj8URJVh/WVW4TAXnzZu48JvRzif++Xeswz6O8+PXdPVp4BG";
+ sout << "TaJv9bBwqV1y7lM/T9FxktP3YIcnbW+ezBUh/logAVeLzCAbYaqChRMUkBizO54DEiA+NBDV5ndu";
+ sout << "Iax8NL9DFp1zmO8gdJBZZLgzf6K8ZbRwwKNlLEkVEZGKei3aVIwo7ed0tjG4aEIodgAuoXD8oa4p";
+ sout << "t7v3sYbn/Wz94AyvAwFV0M1mAMaXqXhpfJSb5CJsSOyKqUtBBhpS58V6Gsq9M9weuwVHee5JI8PI";
+ sout << "bY8WlfQNSVo4JcToIdKPhehz4Ywad3gdX8DhSd+WBT2aMomB71jr3m9CcC9da3oxXjh/jVaN/boQ";
+ sout << "oY5UqFGZ7T1b42x79PiIoOY339sKYR9vr7WPDHTouVtas/3hJBkBKwXqKmBbRPU2N4DTgpt+1zFq";
+ sout << "nig8prSmjiAh9ofp20Pbl5FbYoIdoOfLgYIluAOuT0XhKxLAwWoNGLBA37bGagSxzXnzlDPpFDZ2";
+ sout << "WVdrBwehuD4WhBRxMiTZkzJwhzRkyvsBnO/JqFxXAD5b2CvH9p+3P/czeRv2hRjNZaKHEfdMtIWn";
+ sout << "lPR1zWmZ3LTMBR8R2kmAUt50Sikzj2TpzLlBhemvUVAcv0HEdiILnp3eilOx/ee7GzEroOMHuOGe";
+ sout << "moxWRB1EHj6h2Ya6TVmMb47SzMwKo7mf1PtZ5JLDk61k6Bv9M0WCDiwxlBwC/PjTxHDsTOWRrSJG";
+ sout << "roZ/csy/RQF//nA0f8uKC9HWmGTOsrA6VAVteglGi9k6E9etxvmGCQD2ud2tyz2HSnklJAMutXd+";
+ sout << "flvArk1avpvwXGoNgT3EsEicUGOg93vXl1A873vbHtwnycMzAa8NYjZGW/GPROg8yKkbpoxK+Zel";
+ sout << "+VP14SvqQDKEYDevoGuQWhsQHhW7bYeSa0bSamm9DFzqK2Ld4/aU7JUHYdaAvAJPIHe3F/N8NcJ1";
+ sout << "RE7VoQlrVZXBy33Ly6wwiv1rm8yK4sMdBnNXcxzCyG1NkPsmC/16A08Dy8RV7nJhd1iOJ3gy9BUG";
+ sout << "Y4ofrw/XzITd6vL8mIJW2jyrVzW2OPqMWy6IO/7CHz7d3k5+7KTKWkksTRsuAYWDgZtU5Umph0kN";
+ sout << "/RRnuBRIe/6KYj5/thAY7yLmGFoy8jhDmIikSP/l/pJhUjjgKk1R+oYHGDJ4FSD2KNfRDQ/xHZb2";
+ sout << "++ObYSCHAuhB1HoJBwPcmxkFtxjS047iGXnXo+2nchItcrtifnQTeI0qyV6conJnskM4jfhnKsj7";
+ sout << "A7y4owQjOvkDwu0GueuDOTo/9mW2NjAaiHCp8yarSV1dPI1b/XR231+p5IEp1zWzqFr+O3pDAL8F";
+ sout << "+eU/vj8taOxtT0CcT0gW2rRr8oTigRWCUGP1hxDBdhJtAa7Q+CuFvmtpjm/4fmbroJ5ZVNA/71FN";
+ sout << "yL9DKBmiVTwljf+yRpTGhpMG+xky30zS2R150N93YDDXVT9StjKaOrtLap+9w7BtCvXGdPiyR2QN";
+ sout << "g7gqzrz31poE36fAwM4san1jbbTC+eYcTErQ2wXCQkVne3kbVOwErB0ayl7rNqkw5b3gAME4+DnN";
+ sout << "IM13kdtxY2WeBND96g2enTmFizxHWFzW2asW4/XqGt8EVmzTB4XM/Ytd+XXaNadRUHh44wiNIhPp";
+ sout << "txmIbtkSesyQ4YYSmUYEEcYkZwfcRxHUAGCcnQbSKGLq+N5IcyiLVwhXDfK4fqxH7Oi5DmOwAVmV";
+ sout << "kdDQ6GP7wDcrkAQS9s6fL04bNf7rodacAPdX4HwIKa2YykdXWOiQhp6BRxjUG44AVV5fiTGP1WVn";
+ sout << "MJKXYzSyY5oN3ADAT5em+cIYYVPnsnZBuUzAjHAw3WYj4VlRIrmP+oPdKPFncEyfTn1G7DbmyaPd";
+ sout << "TL3DdB8EDImfZ+A2UMr2i7jynH/fFXzsi2PM9cFKxCsEqG2LGr7KZDP2FFEVvWwIDnvUClj9nrHd";
+ sout << "zyioiild+DW6PoYvqFQX4LUf9Jr09RiJuIvz35I/15pBQbSnTxD1RFJwR92k0yA3514jYBAtfLmf";
+ sout << "/1refalgDjOyD1ntgp3INSYSbpR3TqNIynWwSJGxq9I5aFJypV3Nq8w2Rn3/kld9nqDaTG79ns13";
+ sout << "dwfPOiIZyfdrcxkYOtS4+iijs+YE3JhRKVWMf6ub0cVXttJGORgpzgkSoDWNVZ6O3hVydCziYzoS";
+ sout << "RgHUH2Oas+aZK5IF3Z3aaRYc0A+wy/PEx84LRHsAYdPUQJr+bGseC4wScP1Dyc3xpeJSR1V9t2tc";
+ sout << "AMbhtwcKGX4j5nGnhxSevKzbCDteEnB23TnSQwbuWYmzhB77V3jpu1Cm2h7FcKGM8vPbAQeRBr1b";
+ sout << "+RY95s8hsZGi/USiu4TQ/wHZfEGYcHuVBI920d84pPRVe5EJ8+FzZj+Qy7JwriqLN+7WyUCFdwxn";
+ sout << "4B+WXHTe2epBJMQzlE25kKDHKb2lDDv5HzVUlrZK4rEShkPNv8SB3U9u20GTLlHJbM8RDvPkNjmu";
+ sout << "U4ZLDSJylDaRHWqgchgMnmX08aprI/o1HbgZ5aiByXAUoHSSGHanyYmW/S0LOW7YZH+jOgxzW68U";
+ sout << "lheNnX6Z26RdMe5Xtkd5jx2jXgIT7HADCN8wWdZEVT7FvXRoxtO3nz30cbOim/+IvB2lt//OcTJU";
+ sout << "BwkyweuhJtiXZV1yY+X2z3dWBjBXVFWidPMMWjTUIwalo9A91RL6ZS25kuBXKm/BV6X/zAHkY+jB";
+ sout << "A7qJGLPe5h6SO3GKPSLv0wE+9G6VIhH2TPLfAd+PpqM+xuUNlWlo5JR6ItOgGHuFdjZeDlISYOID";
+ sout << "CJn4zfaU6M4Dmw+m1wsIiyQy4Cw0DcZYUjwStEfLJu7BRyFI55wEbXJr36PRWpvB2wzkI4z1u2yM";
+ sout << "7bFvguH0teVxtMwQy9S4lT9JlfX8QEqNRsuxzQprPJqj0ie2cFBrvJ2E0FtcuarikbcYAmC1iYdz";
+ sout << "Tc2CRVe60taBHR92AsvuTv5OhCIssVc5W+Lbv5e3S0vLwUprWPhfbth/zNevKNiIeogTJOOTQexo";
+ sout << "4EhJ2pf8QSz+ixlWi5ffYKLKSx03wYBZ3fNIhJDP+Y0mz2pd0IyGhxDrMAxYHhPjoEGCfYX6fYz2";
+ sout << "XQGQ1eTGvNEATqz2v9HxYBicYAcW4mjEcTqsMHMYcboVgqiLxOD+jOHJqNrw+eiuC2Ucu6muQ2es";
+ sout << "Zhbo1UNZO/J9XbsZIKa6t0PX0CSczL02Dti8r5rCQ7yeUgwZFzy5oJSShAuUvBDILXBeDhnuU4W3";
+ sout << "eooTvk0lkb8sNAgkUlvHXgdN9jkfQuHqX453IOffB9TnxopLuxS3R6uuRa5ED2pWkL0L5ceftRv3";
+ sout << "0T/sMlHmTNoQhcJSoINMf7f+WmHa95iD1HolQNFJaDEUzLV1DfD2mntncFZoJ4zlr+b/94qp8s/n";
+ sout << "NM0CyoI4ansElbkkjUs7QQp+43pGXu8sRgg7tva7/3vUwLp3Md+8WkX+uppIhj25nlwfkD6IHxdk";
+ sout << "uFNPNgdIikcM463W56CKek7LufT8wQG13mJOMJCObvhW/EU/yb/88hegDxeVJKrWHRyebllsFbZ9";
+ sout << "UeEWkJPKdA+YHilgfSX0aFgofCDmmh1k/cO2RPqIGIqZSfT//6lFEDdzPcCLp/kd4oq7qh5Ko7lo";
+ sout << "bg4N9n6F90oJI+JFJRLy6bEhZC/7obQlP6FFUUqSpizj18+zTLPUaDpt3/eg9QeXUeKcNlkHYt23";
+ sout << "AqzS6PqB9t4bUr+E81QUxpegh5V0M4OPQJbFQ4/rna/AwZVDmGRjJLKzkWUwpnIv7f2+Gl+91ly2";
+ sout << "ve9Ube6Jf9h9M/j7kppHRARY4QbXauYAcSp3wRaIueJWx36dMsqgzuYfwHIyuhGS3CbC1EHUZwM5";
+ sout << "hgCHFvPGHLM7T7p4w6k0e7n8RZJsDybyDAydW8SfSI6LIeX2st4LOHrdLrpUNPyE9JyuIMCSnPaT";
+ sout << "1XnjdWev4jjMeXxa1XWbzy0AQpeQ0UYA4OpqRSu1DyoPWf4IA+bf012m5Im/1BiGF972Ie/6CNvS";
+ sout << "niYOfmxxLWTihdMtslxiy53y2MW2iDzLxX5nvUSyKXfO1XUlDJGTd/zfUywZcY8cgI/f1IPzr2Lk";
+ sout << "3/YKqkJ2De4IpbixDEkbgAroIaoOZXEGD+yNzXVcyISIhMiKHJERdwVxp4j3duc3M04wrwJMZvtK";
+ sout << "lk5jnn+ILhTxcpboq8gge4CbWziUUj9du6mklxZaeYBBpB6CzlVLitesXieA/zl2JnWzRMD7Ho3r";
+ sout << "LLSqxh9UeFgjFtb3ilKSHNZH6x1DS0hFhEIA";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ };
+
+ fhog_tester a;
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+
diff --git a/ml/dlib/dlib/test/filtering.cpp b/ml/dlib/dlib/test/filtering.cpp
new file mode 100644
index 000000000..61dc88440
--- /dev/null
+++ b/ml/dlib/dlib/test/filtering.cpp
@@ -0,0 +1,166 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/filtering.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/matrix.h>
+#include <dlib/rand.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.filtering");
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename filter_type>
+ double test_filter (
+ filter_type kf,
+ int size
+ )
+ {
+ // This test has a point moving in a circle around the origin. The point
+ // also gets a random bump in a random direction at each time step.
+
+ running_stats<double> rs;
+
+ dlib::rand rnd;
+ int count = 0;
+ const dlib::vector<double,3> z(0,0,1);
+ dlib::vector<double,2> p(10,10), temp;
+ for (int i = 0; i < size; ++i)
+ {
+ // move the point around in a circle
+ p += z.cross(p).normalize()/0.5;
+ // randomly drop measurements
+ if (rnd.get_random_double() < 0.7 || count < 4)
+ {
+ // make a random bump
+ dlib::vector<double,2> pp;
+ pp.x() = rnd.get_random_gaussian()/3;
+ pp.y() = rnd.get_random_gaussian()/3;
+
+ ++count;
+ kf.update(p+pp);
+ }
+ else
+ {
+ kf.update();
+ dlog << LTRACE << "MISSED MEASUREMENT";
+ }
+ // figure out the next position
+ temp = (p+z.cross(p).normalize()/0.5);
+ const double error = length(temp - rowm(kf.get_predicted_next_state(),range(0,1)));
+ rs.add(error);
+
+ dlog << LTRACE << temp << "("<< error << "): " << trans(kf.get_predicted_next_state());
+
+ // test the serialization a few times.
+ if (count < 10)
+ {
+ ostringstream sout;
+ serialize(kf, sout);
+ istringstream sin(sout.str());
+ filter_type temp;
+ deserialize(temp, sin);
+ kf = temp;
+ }
+ }
+
+
+ return rs.mean();
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_kalman_filter()
+ {
+ matrix<double,2,2> R;
+ R = 0.3, 0,
+ 0, 0.3;
+
+ // the variables in the state are
+ // x,y, x velocity, y velocity, x acceleration, and y acceleration
+ matrix<double,6,6> A;
+ A = 1, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 1;
+
+ // the measurements only tell us the positions
+ matrix<double,2,6> H;
+ H = 1, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0;
+
+
+ kalman_filter<6,2> kf;
+ kf.set_measurement_noise(R);
+ matrix<double> pn = 0.01*identity_matrix<double,6>();
+ kf.set_process_noise(pn);
+ kf.set_observation_model(H);
+ kf.set_transition_model(A);
+
+ DLIB_TEST(equal(kf.get_observation_model() , H));
+ DLIB_TEST(equal(kf.get_transition_model() , A));
+ DLIB_TEST(equal(kf.get_measurement_noise() , R));
+ DLIB_TEST(equal(kf.get_process_noise() , pn));
+ DLIB_TEST(equal(kf.get_current_estimation_error_covariance() , identity_matrix(pn)));
+
+ double kf_error = test_filter(kf, 300);
+
+ dlog << LINFO << "kf error: "<< kf_error;
+ DLIB_TEST_MSG(kf_error < 0.75, kf_error);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_rls_filter()
+ {
+
+ rls_filter rls(10, 0.99, 0.1);
+
+ DLIB_TEST(rls.get_window_size() == 10);
+ DLIB_TEST(rls.get_forget_factor() == 0.99);
+ DLIB_TEST(rls.get_c() == 0.1);
+
+ double rls_error = test_filter(rls, 1000);
+
+ dlog << LINFO << "rls error: "<< rls_error;
+ DLIB_TEST_MSG(rls_error < 0.75, rls_error);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class filtering_tester : public tester
+ {
+ public:
+ filtering_tester (
+ ) :
+ tester ("test_filtering",
+ "Runs tests on the filtering stuff (rls and kalman filters).")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_rls_filter();
+ test_kalman_filter();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/find_max_factor_graph_nmplp.cpp b/ml/dlib/dlib/test/find_max_factor_graph_nmplp.cpp
new file mode 100644
index 000000000..2260e92a1
--- /dev/null
+++ b/ml/dlib/dlib/test/find_max_factor_graph_nmplp.cpp
@@ -0,0 +1,787 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/optimization.h>
+#include <dlib/unordered_pair.h>
+#include <dlib/rand.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.find_max_factor_graph_nmplp");
+
+// ----------------------------------------------------------------------------------------
+
+ dlib::rand rnd;
+
+ template <bool fully_connected>
+ class map_problem
+ {
+ /*
+ This is a simple 8 node problem with two cycles in it unless fully_connected is true
+ and then it's a fully connected 8 note graph.
+ */
+
+ public:
+
+ mutable std::map<unordered_pair<int>,std::map<std::pair<int,int>,double> > weights;
+ map_problem()
+ {
+ for (int i = 0; i < 8; ++i)
+ {
+ for (int j = i; j < 8; ++j)
+ {
+ weights[make_unordered_pair(i,j)][make_pair(0,0)] = rnd.get_random_gaussian();
+ weights[make_unordered_pair(i,j)][make_pair(0,1)] = rnd.get_random_gaussian();
+ weights[make_unordered_pair(i,j)][make_pair(1,0)] = rnd.get_random_gaussian();
+ weights[make_unordered_pair(i,j)][make_pair(1,1)] = rnd.get_random_gaussian();
+ }
+ }
+ }
+
+ struct node_iterator
+ {
+ node_iterator() {}
+ node_iterator(unsigned long nid_): nid(nid_) {}
+ bool operator== (const node_iterator& item) const { return item.nid == nid; }
+ bool operator!= (const node_iterator& item) const { return item.nid != nid; }
+
+ node_iterator& operator++()
+ {
+ ++nid;
+ return *this;
+ }
+
+ unsigned long nid;
+ };
+
+ struct neighbor_iterator
+ {
+ neighbor_iterator() : count(0) {}
+
+ bool operator== (const neighbor_iterator& item) const { return item.node_id() == node_id(); }
+ bool operator!= (const neighbor_iterator& item) const { return item.node_id() != node_id(); }
+ neighbor_iterator& operator++()
+ {
+ ++count;
+ return *this;
+ }
+
+ unsigned long node_id () const
+ {
+ if (fully_connected)
+ {
+ if (count < home_node)
+ return count;
+ else
+ return count+1;
+ }
+
+ if (home_node < 4)
+ {
+ if (count == 0)
+ return (home_node + 4 + 1)%4;
+ else if (count == 1)
+ return (home_node + 4 - 1)%4;
+ else
+ return 8; // one past the end
+ }
+ else
+ {
+ if (count == 0)
+ return (home_node + 4 + 1)%4 + 4;
+ else if (count == 1)
+ return (home_node + 4 - 1)%4 + 4;
+ else
+ return 8; // one past the end
+ }
+ }
+
+ unsigned long home_node;
+ unsigned long count;
+ };
+
+ unsigned long number_of_nodes (
+ ) const
+ {
+ return 8;
+ }
+
+ node_iterator begin(
+ ) const
+ {
+ node_iterator temp;
+ temp.nid = 0;
+ return temp;
+ }
+
+ node_iterator end(
+ ) const
+ {
+ node_iterator temp;
+ temp.nid = 8;
+ return temp;
+ }
+
+ neighbor_iterator begin(
+ const node_iterator& it
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.home_node = it.nid;
+ return temp;
+ }
+
+ neighbor_iterator begin(
+ const neighbor_iterator& it
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.home_node = it.node_id();
+ return temp;
+ }
+
+ neighbor_iterator end(
+ const node_iterator&
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.home_node = 9;
+ temp.count = 8;
+ return temp;
+ }
+
+ neighbor_iterator end(
+ const neighbor_iterator&
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.home_node = 9;
+ temp.count = 8;
+ return temp;
+ }
+
+
+ unsigned long node_id (
+ const node_iterator& it
+ ) const
+ {
+ return it.nid;
+ }
+
+ unsigned long node_id (
+ const neighbor_iterator& it
+ ) const
+ {
+ return it.node_id();
+ }
+
+
+ unsigned long num_states (
+ const node_iterator&
+ ) const
+ {
+ return 2;
+ }
+
+ unsigned long num_states (
+ const neighbor_iterator&
+ ) const
+ {
+ return 2;
+ }
+
+ double factor_value (const node_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.nid, it2.nid, s1, s2); }
+ double factor_value (const neighbor_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.node_id(), it2.nid, s1, s2); }
+ double factor_value (const node_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.nid, it2.node_id(), s1, s2); }
+ double factor_value (const neighbor_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.node_id(), it2.node_id(), s1, s2); }
+
+ private:
+
+ double basic_factor_value (
+ unsigned long n1,
+ unsigned long n2,
+ unsigned long s1,
+ unsigned long s2
+ ) const
+ {
+ if (n1 > n2)
+ {
+ swap(n1,n2);
+ swap(s1,s2);
+ }
+ return weights[make_unordered_pair(n1,n2)][make_pair(s1,s2)];
+ }
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ class map_problem_chain
+ {
+ /*
+ This is a chain structured 8 node graph (so no cycles).
+ */
+
+ public:
+
+ mutable std::map<unordered_pair<int>,std::map<std::pair<int,int>,double> > weights;
+ map_problem_chain()
+ {
+ for (int i = 0; i < 7; ++i)
+ {
+ weights[make_unordered_pair(i,i+1)][make_pair(0,0)] = rnd.get_random_gaussian();
+ weights[make_unordered_pair(i,i+1)][make_pair(0,1)] = rnd.get_random_gaussian();
+ weights[make_unordered_pair(i,i+1)][make_pair(1,0)] = rnd.get_random_gaussian();
+ weights[make_unordered_pair(i,i+1)][make_pair(1,1)] = rnd.get_random_gaussian();
+ }
+ }
+
+ struct node_iterator
+ {
+ node_iterator() {}
+ node_iterator(unsigned long nid_): nid(nid_) {}
+ bool operator== (const node_iterator& item) const { return item.nid == nid; }
+ bool operator!= (const node_iterator& item) const { return item.nid != nid; }
+
+ node_iterator& operator++()
+ {
+ ++nid;
+ return *this;
+ }
+
+ unsigned long nid;
+ };
+
+ struct neighbor_iterator
+ {
+ neighbor_iterator() : count(0) {}
+
+ bool operator== (const neighbor_iterator& item) const { return item.node_id() == node_id(); }
+ bool operator!= (const neighbor_iterator& item) const { return item.node_id() != node_id(); }
+ neighbor_iterator& operator++()
+ {
+ ++count;
+ return *this;
+ }
+
+ unsigned long node_id () const
+ {
+ if (count >= 2)
+ return 8;
+ return nid[count];
+ }
+
+ unsigned long nid[2];
+ unsigned int count;
+ };
+
+ unsigned long number_of_nodes (
+ ) const
+ {
+ return 8;
+ }
+
+ node_iterator begin(
+ ) const
+ {
+ node_iterator temp;
+ temp.nid = 0;
+ return temp;
+ }
+
+ node_iterator end(
+ ) const
+ {
+ node_iterator temp;
+ temp.nid = 8;
+ return temp;
+ }
+
+ neighbor_iterator begin(
+ const node_iterator& it
+ ) const
+ {
+ neighbor_iterator temp;
+ if (it.nid == 0)
+ {
+ temp.nid[0] = it.nid+1;
+ temp.nid[1] = 8;
+ }
+ else if (it.nid == 7)
+ {
+ temp.nid[0] = it.nid-1;
+ temp.nid[1] = 8;
+ }
+ else
+ {
+ temp.nid[0] = it.nid-1;
+ temp.nid[1] = it.nid+1;
+ }
+ return temp;
+ }
+
+ neighbor_iterator begin(
+ const neighbor_iterator& it
+ ) const
+ {
+ const unsigned long nid = it.node_id();
+ neighbor_iterator temp;
+ if (nid == 0)
+ {
+ temp.nid[0] = nid+1;
+ temp.nid[1] = 8;
+ }
+ else if (nid == 7)
+ {
+ temp.nid[0] = nid-1;
+ temp.nid[1] = 8;
+ }
+ else
+ {
+ temp.nid[0] = nid-1;
+ temp.nid[1] = nid+1;
+ }
+ return temp;
+ }
+
+ neighbor_iterator end(
+ const node_iterator&
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.nid[0] = 8;
+ temp.nid[1] = 8;
+ return temp;
+ }
+
+ neighbor_iterator end(
+ const neighbor_iterator&
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.nid[0] = 8;
+ temp.nid[1] = 8;
+ return temp;
+ }
+
+
+ unsigned long node_id (
+ const node_iterator& it
+ ) const
+ {
+ return it.nid;
+ }
+
+ unsigned long node_id (
+ const neighbor_iterator& it
+ ) const
+ {
+ return it.node_id();
+ }
+
+
+ unsigned long num_states (
+ const node_iterator&
+ ) const
+ {
+ return 2;
+ }
+
+ unsigned long num_states (
+ const neighbor_iterator&
+ ) const
+ {
+ return 2;
+ }
+
+ double factor_value (const node_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.nid, it2.nid, s1, s2); }
+ double factor_value (const neighbor_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.node_id(), it2.nid, s1, s2); }
+ double factor_value (const node_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.nid, it2.node_id(), s1, s2); }
+ double factor_value (const neighbor_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.node_id(), it2.node_id(), s1, s2); }
+
+ private:
+
+ double basic_factor_value (
+ unsigned long n1,
+ unsigned long n2,
+ unsigned long s1,
+ unsigned long s2
+ ) const
+ {
+ if (n1 > n2)
+ {
+ swap(n1,n2);
+ swap(s1,s2);
+ }
+ return weights[make_unordered_pair(n1,n2)][make_pair(s1,s2)];
+ }
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+
+ class map_problem2
+ {
+ /*
+ This is a simple tree structured graph. In particular, it is a star made
+ up of 6 nodes.
+ */
+ public:
+ matrix<double> numbers;
+
+ map_problem2()
+ {
+ numbers = randm(5,3,rnd);
+ }
+
+ struct node_iterator
+ {
+ node_iterator() {}
+ node_iterator(unsigned long nid_): nid(nid_) {}
+ bool operator== (const node_iterator& item) const { return item.nid == nid; }
+ bool operator!= (const node_iterator& item) const { return item.nid != nid; }
+
+ node_iterator& operator++()
+ {
+ ++nid;
+ return *this;
+ }
+
+ unsigned long nid;
+ };
+
+ struct neighbor_iterator
+ {
+ neighbor_iterator() : count(0) {}
+
+ bool operator== (const neighbor_iterator& item) const { return item.node_id() == node_id(); }
+ bool operator!= (const neighbor_iterator& item) const { return item.node_id() != node_id(); }
+ neighbor_iterator& operator++()
+ {
+ ++count;
+ return *this;
+ }
+
+ unsigned long node_id () const
+ {
+ if (home_node == 6)
+ return 6;
+
+ if (home_node < 5)
+ {
+ // all the nodes are connected to node 5 and nothing else
+ if (count == 0)
+ return 5;
+ else
+ return 6; // the number returned by the end() functions.
+ }
+ else if (count < 5)
+ {
+ return count;
+ }
+ else
+ {
+ return 6;
+ }
+
+ }
+
+ unsigned long home_node;
+ unsigned long count;
+ };
+
+ unsigned long number_of_nodes (
+ ) const
+ {
+ return 6;
+ }
+
+ node_iterator begin(
+ ) const
+ {
+ node_iterator temp;
+ temp.nid = 0;
+ return temp;
+ }
+
+ node_iterator end(
+ ) const
+ {
+ node_iterator temp;
+ temp.nid = 6;
+ return temp;
+ }
+
+ neighbor_iterator begin(
+ const node_iterator& it
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.home_node = it.nid;
+ return temp;
+ }
+
+ neighbor_iterator begin(
+ const neighbor_iterator& it
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.home_node = it.node_id();
+ return temp;
+ }
+
+ neighbor_iterator end(
+ const node_iterator&
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.home_node = 6;
+ return temp;
+ }
+
+ neighbor_iterator end(
+ const neighbor_iterator&
+ ) const
+ {
+ neighbor_iterator temp;
+ temp.home_node = 6;
+ return temp;
+ }
+
+
+ unsigned long node_id (
+ const node_iterator& it
+ ) const
+ {
+ return it.nid;
+ }
+
+ unsigned long node_id (
+ const neighbor_iterator& it
+ ) const
+ {
+ return it.node_id();
+ }
+
+
+ unsigned long num_states (
+ const node_iterator&
+ ) const
+ {
+ return 3;
+ }
+
+ unsigned long num_states (
+ const neighbor_iterator&
+ ) const
+ {
+ return 3;
+ }
+
+ double factor_value (const node_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.nid, it2.nid, s1, s2); }
+ double factor_value (const neighbor_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.node_id(), it2.nid, s1, s2); }
+ double factor_value (const node_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.nid, it2.node_id(), s1, s2); }
+ double factor_value (const neighbor_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const
+ { return basic_factor_value(it1.node_id(), it2.node_id(), s1, s2); }
+
+ private:
+
+ double basic_factor_value (
+ unsigned long n1,
+ unsigned long n2,
+ unsigned long s1,
+ unsigned long s2
+ ) const
+ {
+ if (n1 > n2)
+ {
+ swap(n1,n2);
+ swap(s1,s2);
+ }
+
+
+ // basically ignore the other node in this factor. The node we
+ // are ignoring is the center node of this star graph. So we basically
+ // let it always have a value of 1.
+ if (s2 == 1)
+ return numbers(n1,s1) + 1;
+ else
+ return numbers(n1,s1);
+ }
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename map_problem>
+ double find_total_score (
+ const map_problem& prob,
+ const std::vector<unsigned long>& map_assignment
+ )
+ {
+ typedef typename map_problem::node_iterator node_iterator;
+ typedef typename map_problem::neighbor_iterator neighbor_iterator;
+
+ double score = 0;
+ for (node_iterator i = prob.begin(); i != prob.end(); ++i)
+ {
+ const unsigned long id_i = prob.node_id(i);
+ for (neighbor_iterator j = prob.begin(i); j != prob.end(i); ++j)
+ {
+ const unsigned long id_j = prob.node_id(j);
+ score += prob.factor_value(i,j, map_assignment[id_i], map_assignment[id_j]);
+ }
+ }
+
+ return score;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+
+ template <
+ typename map_problem
+ >
+ void brute_force_find_max_factor_graph_nmplp (
+ const map_problem& prob,
+ std::vector<unsigned long>& map_assignment
+ )
+ {
+ std::vector<unsigned long> temp_assignment;
+ temp_assignment.resize(prob.number_of_nodes(),0);
+
+ double best_score = -std::numeric_limits<double>::infinity();
+
+ for (unsigned long i = 0; i < 255; ++i)
+ {
+ temp_assignment[0] = (i&0x01)!=0;
+ temp_assignment[1] = (i&0x02)!=0;
+ temp_assignment[2] = (i&0x04)!=0;
+ temp_assignment[3] = (i&0x08)!=0;
+ temp_assignment[4] = (i&0x10)!=0;
+ temp_assignment[5] = (i&0x20)!=0;
+ temp_assignment[6] = (i&0x40)!=0;
+ temp_assignment[7] = (i&0x80)!=0;
+
+ double score = find_total_score(prob,temp_assignment);
+ if (score > best_score)
+ {
+ best_score = score;
+ map_assignment = temp_assignment;
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename map_problem>
+ void do_test(
+ )
+ {
+ print_spinner();
+ std::vector<unsigned long> map_assignment1, map_assignment2;
+ map_problem prob;
+ find_max_factor_graph_nmplp(prob, map_assignment1, 1000, 1e-8);
+
+ const double score1 = find_total_score(prob, map_assignment1);
+
+ brute_force_find_max_factor_graph_nmplp(prob, map_assignment2);
+ const double score2 = find_total_score(prob, map_assignment2);
+
+ dlog << LINFO << "score NMPLP: " << score1;
+ dlog << LINFO << "score MAP: " << score2;
+
+ DLIB_TEST(std::abs(score1 - score2) < 1e-10);
+ DLIB_TEST(mat(map_assignment1) == mat(map_assignment2));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename map_problem>
+ void do_test2(
+ )
+ {
+ print_spinner();
+ std::vector<unsigned long> map_assignment1, map_assignment2;
+ map_problem prob;
+ find_max_factor_graph_nmplp(prob, map_assignment1, 10, 1e-8);
+
+ const double score1 = find_total_score(prob, map_assignment1);
+
+ map_assignment2.resize(6);
+ map_assignment2[0] = index_of_max(rowm(prob.numbers,0));
+ map_assignment2[1] = index_of_max(rowm(prob.numbers,1));
+ map_assignment2[2] = index_of_max(rowm(prob.numbers,2));
+ map_assignment2[3] = index_of_max(rowm(prob.numbers,3));
+ map_assignment2[4] = index_of_max(rowm(prob.numbers,4));
+ map_assignment2[5] = 1;
+ const double score2 = find_total_score(prob, map_assignment2);
+
+ dlog << LINFO << "score NMPLP: " << score1;
+ dlog << LINFO << "score MAP: " << score2;
+ dlog << LINFO << "MAP assignment: "<< trans(mat(map_assignment1));
+
+ DLIB_TEST(std::abs(score1 - score2) < 1e-10);
+ DLIB_TEST(mat(map_assignment1) == mat(map_assignment2));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_find_max_factor_graph_nmplp : public tester
+ {
+ public:
+ test_find_max_factor_graph_nmplp (
+ ) :
+ tester ("test_find_max_factor_graph_nmplp",
+ "Runs tests on the find_max_factor_graph_nmplp routine.")
+ {}
+
+ void perform_test (
+ )
+ {
+ rnd.clear();
+
+ dlog << LINFO << "test on a chain structured graph";
+ for (int i = 0; i < 30; ++i)
+ do_test<map_problem_chain>();
+
+ dlog << LINFO << "test on a 2 cycle graph";
+ for (int i = 0; i < 30; ++i)
+ do_test<map_problem<false> >();
+
+ dlog << LINFO << "test on a fully connected graph";
+ for (int i = 0; i < 5; ++i)
+ do_test<map_problem<true> >();
+
+ dlog << LINFO << "test on a tree structured graph";
+ for (int i = 0; i < 10; ++i)
+ do_test2<map_problem2>();
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/find_max_factor_graph_viterbi.cpp b/ml/dlib/dlib/test/find_max_factor_graph_viterbi.cpp
new file mode 100644
index 000000000..82754aefd
--- /dev/null
+++ b/ml/dlib/dlib/test/find_max_factor_graph_viterbi.cpp
@@ -0,0 +1,217 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/optimization.h>
+#include <dlib/rand.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.find_max_factor_graph_viterbi");
+
+// ----------------------------------------------------------------------------------------
+
+ dlib::rand rnd;
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ unsigned long O,
+ unsigned long NS,
+ unsigned long num_nodes,
+ bool all_negative
+ >
+ class map_problem
+ {
+ public:
+ unsigned long order() const { return O; }
+ unsigned long num_states() const { return NS; }
+
+ map_problem()
+ {
+ data = randm(number_of_nodes(),(long)std::pow(num_states(),(double)order()+1), rnd);
+ if (all_negative)
+ data = -data;
+ }
+
+ unsigned long number_of_nodes (
+ ) const
+ {
+ return num_nodes;
+ }
+
+ template <
+ typename EXP
+ >
+ double factor_value (
+ unsigned long node_id,
+ const matrix_exp<EXP>& node_states
+ ) const
+ {
+ if (node_states.size() == 1)
+ return data(node_id, node_states(0));
+ else if (node_states.size() == 2)
+ return data(node_id, node_states(0) + node_states(1)*NS);
+ else if (node_states.size() == 3)
+ return data(node_id, (node_states(0) + node_states(1)*NS)*NS + node_states(2));
+ else
+ return data(node_id, ((node_states(0) + node_states(1)*NS)*NS + node_states(2))*NS + node_states(3));
+ }
+
+ matrix<double> data;
+ };
+
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename map_problem
+ >
+ void brute_force_find_max_factor_graph_viterbi (
+ const map_problem& prob,
+ std::vector<unsigned long>& map_assignment
+ )
+ {
+ using namespace dlib::impl;
+ const int order = prob.order();
+ const int num_states = prob.num_states();
+
+ map_assignment.resize(prob.number_of_nodes());
+ double best_score = -std::numeric_limits<double>::infinity();
+ matrix<unsigned long,1,0> node_states;
+ node_states.set_size(prob.number_of_nodes());
+ node_states = 0;
+ do
+ {
+ double score = 0;
+ for (unsigned long i = 0; i < prob.number_of_nodes(); ++i)
+ {
+ score += prob.factor_value(i, (colm(node_states,range(i,i-std::min<int>(order,i)))));
+ }
+
+ if (score > best_score)
+ {
+ for (unsigned long i = 0; i < map_assignment.size(); ++i)
+ map_assignment[i] = node_states(i);
+ best_score = score;
+ }
+
+ } while(advance_state(node_states,num_states));
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ unsigned long order,
+ unsigned long num_states,
+ unsigned long num_nodes,
+ bool all_negative
+ >
+ void do_test_()
+ {
+ dlog << LINFO << "order: "<< order
+ << " num_states: " << num_states
+ << " num_nodes: " << num_nodes
+ << " all_negative: " << all_negative;
+
+ for (int i = 0; i < 25; ++i)
+ {
+ print_spinner();
+ map_problem<order,num_states,num_nodes,all_negative> prob;
+ std::vector<unsigned long> assign, assign2;
+ brute_force_find_max_factor_graph_viterbi(prob, assign);
+ find_max_factor_graph_viterbi(prob, assign2);
+
+ DLIB_TEST_MSG(mat(assign) == mat(assign2),
+ trans(mat(assign))
+ << trans(mat(assign2))
+ );
+ }
+ }
+
+ template <
+ unsigned long order,
+ unsigned long num_states,
+ unsigned long num_nodes
+ >
+ void do_test()
+ {
+ do_test_<order,num_states,num_nodes,false>();
+ }
+
+ template <
+ unsigned long order,
+ unsigned long num_states,
+ unsigned long num_nodes
+ >
+ void do_test_negative()
+ {
+ do_test_<order,num_states,num_nodes,true>();
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_find_max_factor_graph_viterbi : public tester
+ {
+ public:
+ test_find_max_factor_graph_viterbi (
+ ) :
+ tester ("test_find_max_factor_graph_viterbi",
+ "Runs tests on the find_max_factor_graph_viterbi routine.")
+ {}
+
+ void perform_test (
+ )
+ {
+ do_test<1,3,0>();
+ do_test<1,3,1>();
+ do_test<1,3,2>();
+ do_test<0,3,2>();
+ do_test_negative<0,3,2>();
+
+ do_test<1,3,8>();
+ do_test<2,3,7>();
+ do_test_negative<2,3,7>();
+ do_test<3,3,8>();
+ do_test<4,3,8>();
+ do_test_negative<4,3,8>();
+ do_test<0,3,8>();
+ do_test<4,3,1>();
+ do_test<4,3,0>();
+
+ do_test<3,2,1>();
+ do_test<3,2,0>();
+ do_test<3,2,2>();
+ do_test<2,2,1>();
+ do_test_negative<3,2,1>();
+ do_test_negative<3,2,0>();
+ do_test_negative<3,2,2>();
+ do_test_negative<2,2,1>();
+
+ do_test<0,3,0>();
+ do_test<1,2,8>();
+ do_test<2,2,7>();
+ do_test<3,2,8>();
+ do_test<0,2,8>();
+
+ do_test<1,1,8>();
+ do_test<2,1,8>();
+ do_test<3,1,8>();
+ do_test<0,1,8>();
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/find_optimal_parameters.cpp b/ml/dlib/dlib/test/find_optimal_parameters.cpp
new file mode 100644
index 000000000..9f2f5b348
--- /dev/null
+++ b/ml/dlib/dlib/test/find_optimal_parameters.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/optimization/find_optimal_parameters.h>
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.find_optimal_parameters");
+
+// ----------------------------------------------------------------------------------------
+
+
+ class find_optimal_parameters : public tester
+ {
+ public:
+ find_optimal_parameters (
+ ) :
+ tester ("test_find_optimal_parameters",
+ "Runs tests on find_optimal_parameters().")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ matrix<double,0,1> params = {0.5, 0.5};
+ dlib::find_optimal_parameters(4, 0.001, 100, params, {-0.1, -0.01}, {5, 5}, [](const matrix<double,0,1>& params) {
+ cout << ".";
+ return sum(squared(params));
+ });
+
+ matrix<double,0,1> true_params = {0,0};
+
+ DLIB_TEST(max(abs(true_params - params)) < 1e-10);
+
+ params = {0.1};
+ dlib::find_optimal_parameters(4, 0.001, 100, params, {-0.01}, {5}, [](const matrix<double,0,1>& params) {
+ cout << ".";
+ return sum(squared(params));
+ });
+
+ true_params = {0};
+ DLIB_TEST(max(abs(true_params - params)) < 1e-10);
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/geometry.cpp b/ml/dlib/dlib/test/geometry.cpp
new file mode 100644
index 000000000..505a83d95
--- /dev/null
+++ b/ml/dlib/dlib/test/geometry.cpp
@@ -0,0 +1,883 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/geometry.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/string.h>
+#include <dlib/matrix.h>
+#include <dlib/rand.h>
+#include <dlib/array2d.h>
+#include <dlib/image_transforms.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.geometry");
+
+ void geometry_test (
+ )
+ /*!
+ ensures
+ - runs tests on the geometry stuff compliance with the specs
+ !*/
+ {
+ print_spinner();
+
+ point p1;
+ point p2(2,3);
+
+ DLIB_TEST(p1.x() == 0);
+ DLIB_TEST(p1.y() == 0);
+ DLIB_TEST(p2.x() == 2);
+ DLIB_TEST(p2.y() == 3);
+
+ DLIB_TEST((-p2).x() == -2);
+ DLIB_TEST((-p2).y() == -3);
+
+
+ p2 += p2;
+ DLIB_TEST(p2.x() == 4);
+ DLIB_TEST(p2.y() == 6);
+
+ dlib::vector<double> v1 = point(1,0);
+ dlib::vector<double> v2(0,0,1);
+
+ p1 = v2.cross(v1);
+ DLIB_TEST(p1 == point(0,1));
+ DLIB_TEST(p1 != point(1,1));
+ DLIB_TEST(p1 != point(1,0));
+
+ p1 = point(2,3);
+ rectangle rect1 = p1;
+ DLIB_TEST(rect1.width() == 1);
+ DLIB_TEST(rect1.height() == 1);
+ p2 = point(1,1);
+
+ rect1 += p2;
+ DLIB_TEST(rect1.left() == 1);
+ DLIB_TEST(rect1.top() == 1);
+ DLIB_TEST(rect1.right() == 2);
+ DLIB_TEST(rect1.bottom() == 3);
+
+ DLIB_TEST(rect1.width() == 2);
+ DLIB_TEST(rect1.height() == 3);
+
+ // test the iostream << and >> operators (via string_cast and cast_to_string)
+ DLIB_TEST(string_cast<point>(" (1, 2 )") == point(1,2));
+ DLIB_TEST(string_cast<point>(" ( -1, 2 )") == point(-1,2));
+ DLIB_TEST(string_cast<rectangle>(" [(1, 2 )(3,4)]") == rectangle(1,2,3,4));
+ DLIB_TEST(string_cast<dlib::vector<double> >(" (1, 2 , 3.5)") == dlib::vector<double>(1,2,3.5));
+
+ DLIB_TEST(string_cast<rectangle>(cast_to_string(rect1)) == rect1);
+ DLIB_TEST(string_cast<point>(cast_to_string(p1)) == p1);
+ DLIB_TEST(string_cast<dlib::vector<double> >(cast_to_string(v1)) == v1);
+
+ rectangle rect2;
+
+ // test the serialization code
+ ostringstream sout;
+ serialize(rect1,sout);
+ serialize(p1,sout);
+ serialize(v1,sout);
+ serialize(rect1,sout);
+ serialize(p1,sout);
+ serialize(v1,sout);
+
+ istringstream sin(sout.str());
+
+ deserialize(rect2,sin);
+ deserialize(p2,sin);
+ deserialize(v2,sin);
+ DLIB_TEST(rect2 == rect1);
+ DLIB_TEST(p2 == p1);
+ DLIB_TEST(v2 == v1);
+ deserialize(rect2,sin);
+ deserialize(p2,sin);
+ deserialize(v2,sin);
+ DLIB_TEST(rect2 == rect1);
+ DLIB_TEST(p2 == p1);
+ DLIB_TEST(v2 == v1);
+ DLIB_TEST(sin.good());
+ DLIB_TEST(sin.get() == EOF);
+
+
+ v1.x() = 1;
+ v1.y() = 2;
+ v1.z() = 3;
+
+ matrix<double> mv = v1;
+ DLIB_TEST(mv.nr() == 3);
+ DLIB_TEST(mv.nc() == 1);
+ DLIB_TEST(mv(0) == 1);
+ DLIB_TEST(mv(1) == 2);
+ DLIB_TEST(mv(2) == 3);
+
+ set_all_elements(mv,0);
+ DLIB_TEST(mv(0) == 0);
+ DLIB_TEST(mv(1) == 0);
+ DLIB_TEST(mv(2) == 0);
+
+ mv(0) = 5;
+ mv(1) = 6;
+ mv(2) = 7;
+
+ v1 = mv;
+ DLIB_TEST(v1.x() == 5);
+ DLIB_TEST(v1.y() == 6);
+ DLIB_TEST(v1.z() == 7);
+
+
+ {
+ dlib::vector<double,2> vd2;
+ dlib::vector<double,3> vd3;
+ dlib::vector<long,2> vl2;
+ dlib::vector<long,3> vl3;
+
+ vd2.x() = 2.3;
+ vd2.y() = 4.7;
+
+ vd3.z() = 9;
+
+ vd3 = vd2;
+
+
+
+ vl2 = vd3;
+ vl3 = vd3;
+
+
+ DLIB_TEST(vd2.z() == 0);
+ DLIB_TEST(vd3.z() == 0);
+ DLIB_TEST(vl2.z() == 0);
+ DLIB_TEST(vl3.z() == 0);
+
+ DLIB_TEST(vl2.x() == 2);
+ DLIB_TEST(vl3.x() == 2);
+ DLIB_TEST(vl2.y() == 5);
+ DLIB_TEST(vl3.y() == 5);
+
+
+ DLIB_TEST(abs(vd2.cross(vd3).dot(vd2)) < 1e-7);
+ DLIB_TEST(abs(vd3.cross(vd2).dot(vd2)) < 1e-7);
+ DLIB_TEST(abs(vd2.cross(vd3).dot(vd3)) < 1e-7);
+ DLIB_TEST(abs(vd3.cross(vd2).dot(vd3)) < 1e-7);
+
+ DLIB_TEST(abs(vl2.cross(vl3).dot(vl2)) == 0);
+ DLIB_TEST(abs(vl3.cross(vl2).dot(vl2)) == 0);
+ DLIB_TEST(abs(vl2.cross(vl3).dot(vl3)) == 0);
+ DLIB_TEST(abs(vl3.cross(vl2).dot(vl3)) == 0);
+
+
+ DLIB_TEST((vd2-vd3).length() < 1e-7);
+
+ DLIB_TEST(vl2 == vl3);
+
+
+ vl2.x() = 0;
+ vl2.y() = 0;
+ vl3 = vl2;
+
+ vl2.x() = 4;
+ vl3.y() = 3;
+
+ DLIB_TEST(vl2.cross(vl3).length() == 12);
+ DLIB_TEST(vl3.cross(vl2).length() == 12);
+
+
+ matrix<double> m(3,3);
+ m = 1,2,3,
+ 4,5,6,
+ 7,8,9;
+
+ vd3.x() = 2;
+ vd3.y() = 3;
+ vd3.z() = 4;
+
+ vd3 = m*vd3;
+
+ DLIB_TEST_MSG(vd3.x() == 1*2 + 2*3 + 3*4,vd3.x() << " == " << (1*2 + 2*3 + 3*4));
+ DLIB_TEST(vd3.y() == 4*2 + 5*3 + 6*4);
+ DLIB_TEST(vd3.z() == 7*2 + 8*3 + 9*4);
+
+ (vd3*2).dot(vd3);
+ (vd2*2).dot(vd3);
+ (vd3*2).dot(vd2);
+ (vd2*2).dot(vd2);
+ (2*vd3*2).dot(vd3);
+ (2*vd2*2).dot(vd3);
+ (2*vd3*2).dot(vd2);
+ (2*vd2*2).dot(vd2);
+
+ (vd2 + vd3).dot(vd2);
+ (vd2 - vd3).dot(vd2);
+ (vd2/2).dot(vd2);
+ (vd3/2).dot(vd2);
+ }
+
+ {
+ dlib::vector<double,2> vd2;
+ dlib::vector<long,3> vl3;
+
+ vl3.x() = 1;
+ vl3.y() = 2;
+ vl3.z() = 3;
+
+ vd2.x() = 6.5;
+ vd2.y() = 7.5;
+
+ DLIB_TEST((vl3 + vd2).x() == 1+6.5);
+ DLIB_TEST((vl3 + vd2).y() == 2+7.5);
+ DLIB_TEST((vl3 + vd2).z() == 3+0);
+
+ DLIB_TEST((vl3 - vd2).x() == 1-6.5);
+ DLIB_TEST((vl3 - vd2).y() == 2-7.5);
+ DLIB_TEST((vl3 - vd2).z() == 3-0);
+
+ }
+
+ {
+ dlib::vector<double> v(3,4,5);
+ DLIB_TEST((-v).x() == -3.0);
+ DLIB_TEST((-v).y() == -4.0);
+ DLIB_TEST((-v).z() == -5.0);
+ }
+
+ {
+ rectangle rect;
+
+ point tl(2,3);
+ point tr(8,3);
+ point bl(2,9);
+ point br(8,9);
+
+ rect += tl;
+ rect += tr;
+ rect += bl;
+ rect += br;
+
+ DLIB_TEST(rect.tl_corner() == tl);
+ DLIB_TEST(rect.tr_corner() == tr);
+ DLIB_TEST(rect.bl_corner() == bl);
+ DLIB_TEST(rect.br_corner() == br);
+
+ }
+
+ {
+ point p1, center;
+
+ center = point(3,4);
+ p1 = point(10,4);
+
+ DLIB_TEST(rotate_point(center, p1, pi/2) == point(3,7+4));
+
+ center = point(3,3);
+ p1 = point(10,3);
+
+ DLIB_TEST(rotate_point(center, p1, pi/4) == point(8,8));
+ DLIB_TEST(rotate_point(center, p1, -pi/4) == point(8,-2));
+
+ DLIB_TEST(rotate_point(center, p1, pi/4 + 10*pi) == point(8,8));
+ DLIB_TEST(rotate_point(center, p1, -pi/4 + 10*pi) == point(8,-2));
+ DLIB_TEST(rotate_point(center, p1, pi/4 - 10*pi) == point(8,8));
+ DLIB_TEST(rotate_point(center, p1, -pi/4 - 10*pi) == point(8,-2));
+
+ point_rotator rot(pi/2);
+ DLIB_TEST(rot(point(1,0)) == point(0,1));
+ DLIB_TEST(rot(point(0,1)) == point(-1,0));
+ DLIB_TEST(point(rot.get_m()*(dlib::vector<double,2>(1,0))) == point(0,1));
+ DLIB_TEST(point(rot.get_m()*(dlib::vector<double,2>(0,1))) == point(-1,0));
+ }
+
+ {
+ rectangle rect;
+
+ rect = grow_rect(rect,1);
+ DLIB_TEST(rect.width() == 2);
+ DLIB_TEST(rect.height() == 2);
+ DLIB_TEST(rect.left() == -1);
+ DLIB_TEST(rect.top() == -1);
+ DLIB_TEST(rect.right() == 0);
+ DLIB_TEST(rect.bottom() == 0);
+ }
+ {
+ rectangle rect;
+
+ rect = grow_rect(rect,2);
+ DLIB_TEST(rect.width() == 4);
+ DLIB_TEST(rect.height() == 4);
+ DLIB_TEST(rect.left() == -2);
+ DLIB_TEST(rect.top() == -2);
+ DLIB_TEST(rect.right() == 1);
+ DLIB_TEST(rect.bottom() == 1);
+
+ rect = shrink_rect(rect,1);
+ DLIB_TEST(rect.width() == 2);
+ DLIB_TEST(rect.height() == 2);
+ DLIB_TEST(rect.left() == -1);
+ DLIB_TEST(rect.top() == -1);
+ DLIB_TEST(rect.right() == 0);
+ DLIB_TEST(rect.bottom() == 0);
+ }
+ {
+ std::vector< dlib::vector<double> > a;
+
+ dlib::vector<double> v;
+ dlib::rand rnd;
+
+ for (int i = 0; i < 10; ++i)
+ {
+ v.x() = rnd.get_random_double();
+ v.y() = rnd.get_random_double();
+ v.z() = rnd.get_random_double();
+ a.push_back(v);
+
+ }
+
+ // This test is just to make sure the covariance function can compile when used
+ // on a dlib::vector. The actual test doesn't matter.
+ DLIB_TEST(sum(covariance(mat(a))) < 10);
+
+ }
+
+
+ DLIB_TEST(rectangle() + point(5,4) + point(10,10) == rectangle(5,4,10,10));
+
+ // make sure the center of a centered rectangle is always right
+ for (long x = -10; x <= 10; ++x)
+ {
+ for (long y = -10; y <= 10; ++y)
+ {
+ for (long w = 0; w < 10; ++w)
+ {
+ for (long h = 0; h < 10; ++h)
+ {
+ DLIB_TEST(center(centered_rect(x,y,w,h)) == point(x,y));
+ }
+ }
+ }
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_border_enumerator()
+ {
+
+
+
+ border_enumerator be;
+ DLIB_TEST(be.at_start() == true);
+ DLIB_TEST(be.size() == 0);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.move_next() == false);
+ DLIB_TEST(be.at_start() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.move_next() == false);
+ DLIB_TEST(be.at_start() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.size() == 0);
+
+ be = border_enumerator(rectangle(4,4,4,4),1);
+ DLIB_TEST(be.at_start() == true);
+ DLIB_TEST(be.size() == 1);
+ be = border_enumerator(rectangle(4,4,4,4),3);
+ DLIB_TEST(be.at_start() == true);
+ DLIB_TEST(be.size() == 1);
+ be = border_enumerator(rectangle(4,4,4,4),0);
+ DLIB_TEST(be.at_start() == true);
+ DLIB_TEST(be.size() == 0);
+ be = border_enumerator(rectangle(4,4,5,5),0);
+ DLIB_TEST(be.at_start() == true);
+ DLIB_TEST(be.size() == 0);
+ be = border_enumerator(rectangle(4,4,5,5),1);
+ DLIB_TEST(be.at_start() == true);
+ DLIB_TEST(be.size() == 4);
+ be = border_enumerator(rectangle(4,4,5,5),2);
+ DLIB_TEST(be.size() == 4);
+ be = border_enumerator(rectangle(4,4,6,6),1);
+ DLIB_TEST(be.size() == 8);
+ be = border_enumerator(rectangle(4,4,6,6),2);
+ DLIB_TEST(be.size() == 9);
+ be = border_enumerator(rectangle(4,4,6,6),3);
+ DLIB_TEST(be.size() == 9);
+ DLIB_TEST(be.at_start() == true);
+
+ array2d<unsigned char> img, img2;
+ for (int size = 1; size < 10; ++size)
+ {
+ for (int bs = 0; bs < 4; ++bs)
+ {
+ img.set_size(size,size);
+ img2.set_size(size,size);
+
+ assign_all_pixels(img, 1);
+ assign_all_pixels(img2, 1);
+
+ zero_border_pixels(img2, bs,bs);
+
+ be = border_enumerator(get_rect(img),bs);
+ DLIB_TEST(be.at_start() == true);
+ DLIB_TEST(be.current_element_valid() == false);
+ while (be.move_next())
+ {
+ DLIB_TEST(be.at_start() == false);
+ DLIB_TEST(be.current_element_valid() == true);
+ DLIB_TEST_MSG(get_rect(img).contains(be.element()) == true,
+ get_rect(img) << " " << be.element()
+ );
+ const point p = be.element();
+ img[p.y()][p.x()] = 0;
+ }
+ DLIB_TEST(be.at_start() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.move_next() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.move_next() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.at_start() == false);
+
+ DLIB_TEST(mat(img) == mat(img2));
+
+ }
+ }
+
+ for (int size = 1; size < 10; ++size)
+ {
+ for (int bs = 0; bs < 4; ++bs)
+ {
+ img.set_size(size,size+5);
+ img2.set_size(size,size+5);
+
+ assign_all_pixels(img, 1);
+ assign_all_pixels(img2, 1);
+
+ zero_border_pixels(img2, bs,bs);
+
+ const point shift(4,5);
+
+ be = border_enumerator(translate_rect(get_rect(img),shift),bs);
+ DLIB_TEST(be.at_start() == true);
+ DLIB_TEST(be.current_element_valid() == false);
+ while (be.move_next())
+ {
+ DLIB_TEST(be.current_element_valid() == true);
+ DLIB_TEST(be.at_start() == false);
+ DLIB_TEST_MSG(get_rect(img).contains(be.element()-shift) == true,
+ get_rect(img) << " " << be.element()
+ );
+ const point p = be.element()-shift;
+ img[p.y()][p.x()] = 0;
+ }
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.move_next() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.move_next() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.at_start() == false);
+
+ DLIB_TEST(mat(img) == mat(img2));
+
+ }
+ }
+
+ for (int size = 1; size < 10; ++size)
+ {
+ for (int bs = 0; bs < 4; ++bs)
+ {
+ img.set_size(size+2,size);
+ img2.set_size(size+2,size);
+
+ assign_all_pixels(img, 1);
+ assign_all_pixels(img2, 1);
+
+ zero_border_pixels(img2, bs,bs);
+
+ const point shift(-4,5);
+
+ be = border_enumerator(translate_rect(get_rect(img),shift),bs);
+ DLIB_TEST(be.current_element_valid() == false);
+ while (be.move_next())
+ {
+ DLIB_TEST(be.current_element_valid() == true);
+ DLIB_TEST_MSG(get_rect(img).contains(be.element()-shift) == true,
+ get_rect(img) << " " << be.element()
+ );
+ const point p = be.element()-shift;
+ img[p.y()][p.x()] = 0;
+ }
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.move_next() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.move_next() == false);
+ DLIB_TEST(be.current_element_valid() == false);
+
+ DLIB_TEST(mat(img) == mat(img2));
+
+ }
+ }
+
+ {
+ matrix<bool,4,5> hits, truth;
+ const rectangle rect = rectangle(1,1,4,3);
+
+ border_enumerator be(rect, rectangle(2,2, 3, 3));
+ DLIB_TEST(be.size() == 8);
+ hits = false;
+ while (be.move_next())
+ {
+ DLIB_TEST(rect.contains(be.element()));
+ hits(be.element().y(), be.element().x()) = true;
+ }
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.size() == 8);
+ truth = false;
+ truth(1,1) = truth(1,2) = truth(1,3) = truth(1,4) = truth(2,1) =
+ truth(3,1) = truth(2,4) = truth(3,4) = true;
+ DLIB_TEST_MSG(truth == hits, truth << endl << hits);
+
+
+
+
+ be = border_enumerator(rect, rectangle(0,0, 9, 9));
+ DLIB_TEST(be.size() == 0);
+ hits = false;
+ while (be.move_next())
+ {
+ DLIB_TEST(rect.contains(be.element()));
+ hits(be.element().y(), be.element().x()) = true;
+ }
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.size() == 0);
+ truth = false;
+ DLIB_TEST(truth == hits);
+
+
+
+ be = border_enumerator(rect, rectangle(0,0, 3, 9));
+ DLIB_TEST(be.size() == 3);
+ hits = false;
+ while (be.move_next())
+ {
+ DLIB_TEST(rect.contains(be.element()));
+ hits(be.element().y(), be.element().x()) = true;
+ }
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.size() == 3);
+ truth = false;
+ truth(1,4) = truth(2,4) = truth(3,4) = true;
+ DLIB_TEST(truth == hits);
+
+
+
+
+ be = border_enumerator(rect, rectangle(2,1, 4, 3));
+ DLIB_TEST(be.size() == 3);
+ hits = false;
+ while (be.move_next())
+ {
+ DLIB_TEST(rect.contains(be.element()));
+ hits(be.element().y(), be.element().x()) = true;
+ }
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.size() == 3);
+ truth = false;
+ truth(1,1) = truth(2,1) = truth(3,1) = true;
+ DLIB_TEST(truth == hits);
+
+
+
+ be = border_enumerator(rect, rectangle(1,1, 5, 2));
+ DLIB_TEST(be.size() == 4);
+ hits = false;
+ while (be.move_next())
+ {
+ DLIB_TEST(rect.contains(be.element()));
+ hits(be.element().y(), be.element().x()) = true;
+ }
+ DLIB_TEST(be.current_element_valid() == false);
+ DLIB_TEST(be.size() == 4);
+ truth = false;
+ truth(3,1) = truth(3,2) = truth(3,3) = truth(3,4) = true;
+ DLIB_TEST(truth == hits);
+
+
+
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_find_affine_transform()
+ {
+ //typedef dlib::vector<double,2> vect;
+ typedef point vect;
+ std::vector<vect> from, to;
+
+ from.push_back(vect(0,0));
+ to.push_back(vect(0,1));
+
+ from.push_back(vect(0,1));
+ to.push_back(vect(1,1));
+
+ from.push_back(vect(1,1));
+ to.push_back(vect(1,0));
+
+ from.push_back(vect(1,0));
+ to.push_back(vect(0,0));
+
+ point_transform_affine t = find_affine_transform(from,to);
+ point_transform_affine tinv = inv(t);
+
+ for (unsigned long i = 0; i < from.size(); ++i)
+ {
+ dlog << LINFO << "affine transformation error: "<< length(t(from[i])-to[i]);
+ DLIB_TEST(length(t(from[i])-to[i]) < 1e-14);
+ DLIB_TEST(length(tinv(t(from[i]))-from[i]) < 1e-14);
+ DLIB_TEST(length(t(tinv(from[i]))-from[i]) < 1e-14);
+
+ point_transform_affine temp = t*inv(t);
+ DLIB_TEST(length(temp.get_b()) < 1e-14);
+ DLIB_TEST(max(abs(temp.get_m() - identity_matrix<double>(2))) < 1e-14);
+ }
+
+ ostringstream sout;
+ serialize(t, sout);
+ istringstream sin(sout.str());
+ point_transform_affine t2;
+ DLIB_TEST(length(t2(point(2,3)) - point(2,3)) < 1e-14);
+ deserialize(t2, sin);
+ DLIB_TEST(max(abs(t2.get_m()-t.get_m())) < 1e-14);
+ DLIB_TEST(max(abs(t2.get_b()-t.get_b())) < 1e-14);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ double projective_transform_pass_rate(const double error_rate)
+ {
+ print_spinner();
+ dlog << LINFO << "projective_transform_pass_rate, error_rate: "<< error_rate;
+ dlib::rand rnd;
+ running_stats<double> pass_rate;
+ for (int rounds = 0; rounds < 1000; ++rounds)
+ {
+ running_stats<double> rs, rs_true;
+ matrix<double> H = 2*(randm(3,3,rnd)-0.5);
+
+ H(0,2) = rnd.get_random_gaussian()*10;
+ H(1,2) = rnd.get_random_gaussian()*10;
+
+
+ H(2,0) = rnd.get_random_double()*2.1;
+ H(2,1) = rnd.get_random_double()*2.1;
+ H(2,2) = 1 + rnd.get_random_gaussian()*3.1;
+
+ point_transform_projective tran(H);
+ point_transform_projective traninv = inv(tran);
+
+ const int num = rnd.get_random_32bit_number()%8 + 4;
+
+ std::vector<dlib::vector<double,2> > from_points, to_points;
+ for (int i = 0; i < num; ++i)
+ {
+ dlib::vector<double,2> p = randm(2,1,rnd)*1000;
+ from_points.push_back(p);
+ to_points.push_back(tran(p) + (randm(2,1,rnd)-0.5)*error_rate);
+ DLIB_TEST(length(traninv(tran(p))-p) <= 1e-5);
+ DLIB_TEST(length(tran(traninv(p))-p) <= 1e-5);
+
+ point_transform_projective temp = tran*traninv;
+ DLIB_TEST_MSG(max(abs(temp.get_m() - identity_matrix<double>(3))) < 1e-10, temp.get_m());
+ temp = traninv*tran;
+ DLIB_TEST_MSG(max(abs(temp.get_m() - identity_matrix<double>(3))) < 1e-10, temp.get_m());
+ }
+
+
+ point_transform_projective tran2 = find_projective_transform(from_points, to_points);
+
+ for (unsigned long i = 0; i < from_points.size(); ++i)
+ {
+ const double err = length_squared(tran2(from_points[i]) - to_points[i]);
+ rs.add(err);
+ const double err_true = length_squared(tran(from_points[i]) - to_points[i]);
+ rs_true.add(err_true);
+ }
+
+ if ( rs.mean() < 0.01)
+ {
+ pass_rate.add(1);
+ }
+ else
+ {
+ dlog << LINFO << " errors: mean/max: " << rs.mean() << " " << rs.max();
+ pass_rate.add(0);
+ }
+
+ ostringstream sout;
+ serialize(tran, sout);
+ istringstream sin(sout.str());
+ point_transform_projective tran3;
+ DLIB_TEST(length(tran3(point(2,3)) - point(2,3)) < 1e-14);
+ deserialize(tran3, sin);
+ DLIB_TEST(max(abs(tran3.get_m()-tran.get_m())) < 1e-14);
+ }
+
+ dlog << LINFO << " pass_rate.mean(): "<< pass_rate.mean();
+ return pass_rate.mean();
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ void test_find_similarity_transform()
+ {
+ print_spinner();
+ std::vector<dlib::vector<T,2> > from_points, to_points;
+
+ from_points.push_back(dlib::vector<T,2>(0,0));
+ from_points.push_back(dlib::vector<T,2>(0,1));
+ from_points.push_back(dlib::vector<T,2>(1,0));
+
+ to_points.push_back(dlib::vector<T,2>(8,0));
+ to_points.push_back(dlib::vector<T,2>(6,0));
+ to_points.push_back(dlib::vector<T,2>(8,2));
+
+ point_transform_affine tform = find_similarity_transform(from_points, to_points);
+
+ for (unsigned long i = 0; i < from_points.size(); ++i)
+ {
+ DLIB_TEST(length(tform(from_points[i]) - to_points[i]) < 1e-14);
+ }
+ }
+
+ template <typename T>
+ void test_find_similarity_transform2()
+ {
+ print_spinner();
+ std::vector<dlib::vector<T,2> > from_points, to_points;
+
+ from_points.push_back(dlib::vector<T,2>(0,0));
+ from_points.push_back(dlib::vector<T,2>(0,1));
+
+ to_points.push_back(dlib::vector<T,2>(8,0));
+ to_points.push_back(dlib::vector<T,2>(6,0));
+
+ point_transform_affine tform = find_similarity_transform(from_points, to_points);
+
+ for (unsigned long i = 0; i < from_points.size(); ++i)
+ {
+ DLIB_TEST(length(tform(from_points[i]) - to_points[i]) < 1e-14);
+ }
+ }
+
+
+// ----------------------------------------------------------------------------------------
+
+ void test_rect_to_drect()
+ {
+ print_spinner();
+ dlib::rand rnd;
+ for (int i = 0; i < 5000; ++i)
+ {
+ rectangle rect = centered_rect(rnd.get_random_32bit_number()%100,
+ rnd.get_random_32bit_number()%100,
+ rnd.get_random_32bit_number()%100,
+ rnd.get_random_32bit_number()%100);
+
+ drectangle drect = rect;
+ rectangle rect2 = drect;
+ DLIB_TEST(rect2 == rect);
+ DLIB_TEST(rect.width() == drect.width());
+ DLIB_TEST(rect.height() == drect.height());
+ DLIB_TEST(dcenter(rect) == dcenter(drect));
+ DLIB_TEST(rect.is_empty() == drect.is_empty());
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_affine3d()
+ {
+ const dlib::vector<double> x(1,0,0);
+ const dlib::vector<double> y(0,1,0);
+ const dlib::vector<double> z(0,0,1);
+ const dlib::vector<double> e(1,1,1);
+ const dlib::vector<double> ex(-1,1,1);
+ const dlib::vector<double> ey(1,-1,1);
+ const dlib::vector<double> ez(1,1,-1);
+
+ dlib::vector<double> w;
+
+ w = rotate_around_z(pi/2)(x);
+ DLIB_TEST(length(w-y) < 1e-12);
+ w = rotate_around_z(pi/2)(e);
+ DLIB_TEST(length(w-ex) < 1e-12);
+
+ w = rotate_around_y(-pi/2)(x);
+ DLIB_TEST(length(w-z) < 1e-12);
+ w = rotate_around_y(pi/2)(e);
+ DLIB_TEST(length(w-ez) < 1e-12);
+
+ w = rotate_around_x(pi/2)(y);
+ DLIB_TEST(length(w-z) < 1e-12);
+ w = rotate_around_x(pi/2)(e);
+ DLIB_TEST(length(w-ey) < 1e-12);
+
+ w = translate_point(x)(y);
+ DLIB_TEST(length(w-x-y) < 1e-12);
+
+ point_transform_affine3d tform;
+ tform = rotate_around_x(pi/2)*rotate_around_z(pi/2)*translate_point(x);
+ DLIB_TEST(length(tform(dlib::vector<double>())-z) < 1e-12);
+ DLIB_TEST(length(inv(tform)(z)) < 1e-12);
+
+ point_transform_affine tform2;
+ tform = tform*tform2;// the default tform is the identity mapping so this shouldn't do anything different
+ DLIB_TEST(length(tform(dlib::vector<double>())-z) < 1e-12);
+ DLIB_TEST(length(inv(tform)(z)) < 1e-12);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class geometry_tester : public tester
+ {
+ public:
+ geometry_tester (
+ ) :
+ tester ("test_geometry",
+ "Runs tests on the geometry stuff.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_affine3d();
+ test_rect_to_drect();
+ geometry_test();
+ test_border_enumerator();
+ test_find_affine_transform();
+ DLIB_TEST(projective_transform_pass_rate(0.1) > 0.99);
+ DLIB_TEST(projective_transform_pass_rate(0.0) == 1);
+
+ test_find_similarity_transform<double>();
+ test_find_similarity_transform2<double>();
+ test_find_similarity_transform<float>();
+ test_find_similarity_transform2<float>();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/global_optimization.cpp b/ml/dlib/dlib/test/global_optimization.cpp
new file mode 100644
index 000000000..fee80c81f
--- /dev/null
+++ b/ml/dlib/dlib/test/global_optimization.cpp
@@ -0,0 +1,302 @@
+// Copyright (C) 2017 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/global_optimization.h>
+#include <dlib/statistics.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include <dlib/rand.h>
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.global_optimization");
+
+// ----------------------------------------------------------------------------------------
+
+ void test_upper_bound_function(double relative_noise_magnitude, double solver_eps)
+ {
+ print_spinner();
+
+ dlog << LINFO << "test_upper_bound_function, relative_noise_magnitude="<< relative_noise_magnitude << ", solver_eps=" << solver_eps;
+
+ auto rosen = [](const matrix<double,0,1>& x) { return -1*( 100*std::pow(x(1) - x(0)*x(0),2.0) + std::pow(1 - x(0),2)); };
+
+ dlib::rand rnd;
+ auto make_rnd = [&rnd]() { matrix<double,0,1> x(2); x = 2*rnd.get_random_double(), 2*rnd.get_random_double(); return x; };
+
+
+ std::vector<function_evaluation> evals;
+ for (int i = 0; i < 100; ++i)
+ {
+ auto x = make_rnd();
+ evals.emplace_back(x,rosen(x));
+ }
+
+ upper_bound_function ub(evals, relative_noise_magnitude, solver_eps);
+ DLIB_TEST(ub.num_points() == (long)evals.size());
+ DLIB_TEST(ub.dimensionality() == 2);
+ for (auto& ev : evals)
+ {
+ dlog << LINFO << ub(ev.x) - ev.y;
+ DLIB_TEST_MSG(ub(ev.x) - ev.y > -1e10, ub(ev.x) - ev.y);
+ }
+
+
+ for (int i = 0; i < 100; ++i)
+ {
+ auto x = make_rnd();
+ evals.emplace_back(x,rosen(x));
+ ub.add(evals.back());
+ }
+
+ DLIB_TEST(ub.num_points() == (long)evals.size());
+ DLIB_TEST(ub.dimensionality() == 2);
+
+ for (auto& ev : evals)
+ {
+ dlog << LINFO << ub(ev.x) - ev.y;
+ DLIB_TEST_MSG(ub(ev.x) - ev.y > -1e10, ub(ev.x) - ev.y);
+ }
+
+
+ if (solver_eps < 0.001)
+ {
+ dlog << LINFO << "out of sample points: ";
+ for (int i = 0; i < 10; ++i)
+ {
+ auto x = make_rnd();
+ dlog << LINFO << ub(x) - rosen(x);
+ DLIB_TEST_MSG(ub(x) - rosen(x) > 1e-10, ub(x) - rosen(x));
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ double complex_holder_table ( double x0, double x1)
+ {
+ // The regular HolderTable function
+ //return -std::abs(sin(x0)*cos(x1)*exp(std::abs(1-std::sqrt(x0*x0+x1*x1)/pi)));
+
+ // My more complex version of it with discontinuities and more local minima.
+ double sign = 1;
+ for (double j = -4; j < 9; j += 0.5)
+ {
+ if (j < x0 && x0 < j+0.5)
+ x0 += sign*0.25;
+ sign *= -1;
+ }
+ // HolderTable function tilted towards 10,10
+ return -std::abs(sin(x0)*cos(x1)*exp(std::abs(1-std::sqrt(x0*x0+x1*x1)/pi))) +(x0+x1)/10 + sin(x0*10)*cos(x1*10);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_global_function_search()
+ {
+
+ function_spec spec{{-10,-10}, {10,10}};
+ function_spec spec2{{-10,-10, -50}, {10,10, 50}};
+ global_function_search opt({spec, spec, spec2});
+
+ dlib::rand rnd;
+ bool found_optimal_point = false;
+ for (int i = 0; i < 400 && !found_optimal_point; ++i)
+ {
+ print_spinner();
+ std::vector<function_evaluation_request> nexts;
+ for (int k = 0; k < rnd.get_integer_in_range(1,4); ++k)
+ nexts.emplace_back(opt.get_next_x());
+
+ for (auto& next : nexts)
+ {
+ switch (next.function_idx())
+ {
+ case 0: next.set( -complex_holder_table(next.x()(0), next.x()(1))); break;
+ case 1: next.set( -10*complex_holder_table(next.x()(0), next.x()(1))); break;
+ case 2: next.set( -2*complex_holder_table(next.x()(0), next.x()(1))); break;
+ default: DLIB_TEST(false); break;
+ }
+
+ matrix<double,0,1> x;
+ double y;
+ size_t function_idx;
+ opt.get_best_function_eval(x,y,function_idx);
+ /*
+ cout << "\ni: "<< i << endl;
+ cout << "best eval x: "<< trans(x);
+ cout << "best eval y: "<< y << endl;
+ cout << "best eval function index: "<< function_idx << endl;
+ */
+
+ if (std::abs(y - 10*21.9210397) < 0.0001)
+ {
+ found_optimal_point = true;
+ break;
+ }
+ }
+ }
+
+ DLIB_TEST(found_optimal_point);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_find_max_global(
+ )
+ {
+ print_spinner();
+ auto rosen = [](const matrix<double,0,1>& x) { return -1*( 100*std::pow(x(1) - x(0)*x(0),2.0) + std::pow(1 - x(0),2)); };
+
+ auto result = find_max_global(rosen, {0.1, 0.1}, {2, 2}, max_function_calls(100), 0);
+ matrix<double,0,1> true_x = {1,1};
+
+ dlog << LINFO << "rosen: " << trans(result.x);
+ DLIB_TEST_MSG(max(abs(true_x-result.x)) < 1e-5, max(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_max_global(rosen, {0.1, 0.1}, {2, 2}, max_function_calls(100));
+ dlog << LINFO << "rosen: " << trans(result.x);
+ DLIB_TEST_MSG(max(abs(true_x-result.x)) < 1e-5, max(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_max_global(rosen, {0.1, 0.1}, {2, 2}, std::chrono::seconds(5));
+ dlog << LINFO << "rosen: " << trans(result.x);
+ DLIB_TEST_MSG(max(abs(true_x-result.x)) < 1e-5, max(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_max_global(rosen, {0.1, 0.1}, {2, 2}, {false,false}, max_function_calls(100));
+ dlog << LINFO << "rosen: " << trans(result.x);
+ DLIB_TEST_MSG(max(abs(true_x-result.x)) < 1e-5, max(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_max_global(rosen, {0.1, 0.1}, {0.9, 0.9}, {false,false}, max_function_calls(140));
+ true_x = {0.9, 0.81};
+ dlog << LINFO << "rosen, bounded at 0.9: " << trans(result.x);
+ DLIB_TEST_MSG(max(abs(true_x-result.x)) < 1e-5, max(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_max_global([](double x){ return -std::pow(x-2,2.0); }, -10, 10, max_function_calls(10), 0);
+ dlog << LINFO << "(x-2)^2: " << trans(result.x);
+ DLIB_TEST(result.x.size()==1);
+ DLIB_TEST(std::abs(result.x - 2) < 1e-9);
+ print_spinner();
+
+ result = find_max_global([](double x){ return -std::pow(x-2,2.0); }, -10, 1, max_function_calls(10));
+ dlog << LINFO << "(x-2)^2, bound at 1: " << trans(result.x);
+ DLIB_TEST(result.x.size()==1);
+ DLIB_TEST(std::abs(result.x - 1) < 1e-9);
+ print_spinner();
+
+ result = find_max_global([](double x){ return -std::pow(x-2,2.0); }, -10, 1, std::chrono::seconds(2));
+ dlog << LINFO << "(x-2)^2, bound at 1: " << trans(result.x);
+ DLIB_TEST(result.x.size()==1);
+ DLIB_TEST(std::abs(result.x - 1) < 1e-9);
+ print_spinner();
+
+
+ result = find_max_global([](double a, double b){ return -complex_holder_table(a,b);},
+ {-10, -10}, {10, 10}, max_function_calls(400), 0);
+ dlog << LINFO << "complex_holder_table y: "<< result.y;
+ DLIB_TEST_MSG(std::abs(result.y - 21.9210397) < 0.0001, std::abs(result.y - 21.9210397));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_find_min_global(
+ )
+ {
+ print_spinner();
+ auto rosen = [](const matrix<double,0,1>& x) { return +1*( 100*std::pow(x(1) - x(0)*x(0),2.0) + std::pow(1 - x(0),2)); };
+
+ auto result = find_min_global(rosen, {0.1, 0.1}, {2, 2}, max_function_calls(100), 0);
+ matrix<double,0,1> true_x = {1,1};
+
+ dlog << LINFO << "rosen: " << trans(result.x);
+ DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_min_global(rosen, {0.1, 0.1}, {2, 2}, max_function_calls(100));
+ dlog << LINFO << "rosen: " << trans(result.x);
+ DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_min_global(rosen, {0.1, 0.1}, {2, 2}, std::chrono::seconds(5));
+ dlog << LINFO << "rosen: " << trans(result.x);
+ DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_min_global(rosen, {0.1, 0.1}, {2, 2}, {false,false}, max_function_calls(100));
+ dlog << LINFO << "rosen: " << trans(result.x);
+ DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_min_global(rosen, {0, 0}, {0.9, 0.9}, {false,false}, max_function_calls(100));
+ true_x = {0.9, 0.81};
+ dlog << LINFO << "rosen, bounded at 0.9: " << trans(result.x);
+ DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
+ print_spinner();
+
+ result = find_min_global([](double x){ return std::pow(x-2,2.0); }, -10, 10, max_function_calls(10), 0);
+ dlog << LINFO << "(x-2)^2: " << trans(result.x);
+ DLIB_TEST(result.x.size()==1);
+ DLIB_TEST(std::abs(result.x - 2) < 1e-9);
+ print_spinner();
+
+ result = find_min_global([](double x){ return std::pow(x-2,2.0); }, -10, 1, max_function_calls(10));
+ dlog << LINFO << "(x-2)^2, bound at 1: " << trans(result.x);
+ DLIB_TEST(result.x.size()==1);
+ DLIB_TEST(std::abs(result.x - 1) < 1e-9);
+ print_spinner();
+
+ result = find_min_global([](double x){ return std::pow(x-2,2.0); }, -10, 1, std::chrono::seconds(2));
+ dlog << LINFO << "(x-2)^2, bound at 1: " << trans(result.x);
+ DLIB_TEST(result.x.size()==1);
+ DLIB_TEST(std::abs(result.x - 1) < 1e-9);
+ print_spinner();
+
+
+ result = find_min_global([](double a, double b){ return complex_holder_table(a,b);},
+ {-10, -10}, {10, 10}, max_function_calls(400), 0);
+ dlog << LINFO << "complex_holder_table y: "<< result.y;
+ DLIB_TEST_MSG(std::abs(result.y + 21.9210397) < 0.0001, std::abs(result.y + 21.9210397));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class global_optimization_tester : public tester
+ {
+ public:
+ global_optimization_tester (
+ ) :
+ tester ("test_global_optimization",
+ "Runs tests on the global optimization components.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_upper_bound_function(0.01, 1e-6);
+ test_upper_bound_function(0.0, 1e-6);
+ test_upper_bound_function(0.0, 1e-1);
+ test_global_function_search();
+ test_find_max_global();
+ test_find_min_global();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/graph.cpp b/ml/dlib/dlib/test/graph.cpp
new file mode 100644
index 000000000..0651f3049
--- /dev/null
+++ b/ml/dlib/dlib/test/graph.cpp
@@ -0,0 +1,414 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/graph.h>
+#include <dlib/graph_utils.h>
+#include <dlib/set.h>
+
+#include "tester.h"
+
+// This is called an unnamed-namespace and it has the effect of making everything inside this file "private"
+// so that everything you declare will have static linkage. Thus we won't have any multiply
+// defined symbol errors coming out of the linker when we try to compile the test suite.
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+
+
+ // Declare the logger we will use in this test. The name of the tester
+ // should start with "test."
+ logger dlog("test.graph");
+
+ template <
+ typename graph
+ >
+ void graph_test (
+ )
+ /*!
+ requires
+ - graph is an implementation of graph/graph_kernel_abstract.h
+ is instantiated with int
+ ensures
+ - runs tests on graph for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ COMPILE_TIME_ASSERT(is_graph<graph>::value);
+
+ graph a, b;
+ dlib::set<unsigned long>::compare_1b_c s;
+
+ DLIB_TEST(graph_contains_length_one_cycle(a) == false);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+
+ DLIB_TEST(a.number_of_nodes() == 0);
+
+ a.set_number_of_nodes(5);
+ DLIB_TEST(graph_is_connected(a) == false);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+ DLIB_TEST(a.number_of_nodes() == 5);
+ DLIB_TEST(graph_contains_length_one_cycle(a) == false);
+
+ for (int i = 0; i < 5; ++i)
+ {
+ a.node(i).data = i;
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+
+ a.remove_node(1);
+
+ DLIB_TEST(a.number_of_nodes() == 4);
+
+
+ // make sure that only the number with data == 1 was removed
+ int count = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ count += a.node(i).data;
+ DLIB_TEST(a.node(i).number_of_neighbors() == 0);
+ DLIB_TEST(a.node(i).index() == (unsigned int)i);
+ }
+
+ DLIB_TEST(count == 9);
+
+
+ a.add_edge(1,1);
+ DLIB_TEST(graph_contains_length_one_cycle(a) == true);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+ DLIB_TEST(a.has_edge(1,1));
+ DLIB_TEST(a.node(1).number_of_neighbors() == 1);
+
+ a.add_edge(1,3);
+ DLIB_TEST(a.node(1).number_of_neighbors() == 2);
+ DLIB_TEST(a.node(2).number_of_neighbors() == 0);
+ DLIB_TEST(a.node(3).number_of_neighbors() == 1);
+ DLIB_TEST(a.has_edge(1,1));
+ DLIB_TEST(a.has_edge(1,3));
+ DLIB_TEST(a.has_edge(3,1));
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+ a.remove_edge(1,1);
+ DLIB_TEST(graph_contains_length_one_cycle(a) == false);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+ DLIB_TEST(a.node(1).number_of_neighbors() == 1);
+ DLIB_TEST(a.node(2).number_of_neighbors() == 0);
+ DLIB_TEST(a.node(3).number_of_neighbors() == 1);
+ DLIB_TEST(a.has_edge(1,1) == false);
+ DLIB_TEST(a.has_edge(1,3));
+ DLIB_TEST(a.has_edge(3,1));
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+
+ swap(a,b);
+
+
+ DLIB_TEST(graph_contains_undirected_cycle(b) == false);
+ DLIB_TEST(b.node(1).number_of_neighbors() == 1);
+ DLIB_TEST(b.node(2).number_of_neighbors() == 0);
+ DLIB_TEST(b.node(3).number_of_neighbors() == 1);
+ DLIB_TEST(b.has_edge(1,1) == false);
+ DLIB_TEST(b.has_edge(1,3));
+ DLIB_TEST(b.has_edge(3,1));
+ DLIB_TEST(graph_contains_undirected_cycle(b) == false);
+
+ DLIB_TEST(a.number_of_nodes() == 0);
+ DLIB_TEST(b.number_of_nodes() == 4);
+
+ copy_graph_structure(b,b);
+ DLIB_TEST(b.number_of_nodes() == 4);
+
+ b.add_edge(1,2);
+ DLIB_TEST(graph_contains_undirected_cycle(b) == false);
+ DLIB_TEST(graph_contains_undirected_cycle(b) == false);
+ b.add_edge(3,2);
+ DLIB_TEST(graph_contains_undirected_cycle(b) == true);
+ b.add_edge(1,1);
+ DLIB_TEST(graph_is_connected(b) == false);
+ b.add_edge(0,2);
+ DLIB_TEST(graph_is_connected(b) == true);
+
+ DLIB_TEST(graph_contains_undirected_cycle(b) == true);
+
+ DLIB_TEST(a.number_of_nodes() == 0);
+
+ for (unsigned long i = 0; i < b.number_of_nodes(); ++i)
+ {
+ for (unsigned long j = 0; j < b.node(i).number_of_neighbors(); ++j)
+ {
+ b.node(i).edge(j) = 'c';
+ }
+ }
+
+ b.node(1).edge(0) = 'a';
+ const unsigned long e1 = b.node(1).neighbor(0).index();
+ b.node(0).edge(0) = 'n';
+ const unsigned long e2 = b.node(0).neighbor(0).index();
+
+ ostringstream sout;
+ serialize(b, sout);
+ istringstream sin(sout.str());
+
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+
+ a.set_number_of_nodes(10);
+ deserialize(a, sin);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+
+ for (unsigned long i = 0; i < a.number_of_nodes(); ++i)
+ {
+ for (unsigned long j = 0; j < a.node(i).number_of_neighbors(); ++j)
+ {
+ if ((i == 0 && a.node(i).neighbor(j).index() == e2) ||
+ (i == e2 && a.node(i).neighbor(j).index() == 0) )
+ {
+ DLIB_TEST(a.node(i).edge(j) == 'n');
+ }
+ else if ((i == 1 && a.node(i).neighbor(j).index() == e1) ||
+ (i == e1 && a.node(i).neighbor(j).index() == 1))
+ {
+ DLIB_TEST(a.node(i).edge(j) == 'a');
+ }
+ else
+ {
+ DLIB_TEST(i != 0 || a.node(i).neighbor(j).index() != e2);
+ DLIB_TEST_MSG(a.node(i).edge(j) == 'c',a.node(i).edge(j));
+ }
+ }
+ }
+
+ DLIB_TEST(a.number_of_nodes() == 4);
+ DLIB_TEST(a.has_edge(1,2) == true);
+ DLIB_TEST(a.has_edge(3,2) == true);
+ DLIB_TEST(a.has_edge(1,1) == true);
+ DLIB_TEST(a.has_edge(0,2) == true);
+ DLIB_TEST(a.has_edge(1,3) == true);
+ DLIB_TEST(a.has_edge(0,1) == false);
+ DLIB_TEST(a.has_edge(0,3) == false);
+ DLIB_TEST(a.has_edge(0,0) == false);
+ DLIB_TEST(a.has_edge(1,0) == false);
+ DLIB_TEST(a.has_edge(3,0) == false);
+
+
+ for (unsigned long i = 0; i < a.number_of_nodes(); ++i)
+ {
+ a.node(i).data = static_cast<int>(i);
+ }
+
+ a.remove_node(2);
+ DLIB_TEST(a.number_of_nodes() == 3);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+
+ count = 0;
+ for (unsigned long i = 0; i < a.number_of_nodes(); ++i)
+ {
+ if (a.node(i).data == 0)
+ {
+ DLIB_TEST(a.node(i).number_of_neighbors() == 0);
+ }
+ else if (a.node(i).data == 1)
+ {
+ DLIB_TEST(a.node(i).number_of_neighbors() == 2);
+ }
+ else if (a.node(i).data == 3)
+ {
+ DLIB_TEST(a.node(i).number_of_neighbors() == 1);
+ }
+ else
+ {
+ DLIB_TEST_MSG(false,"this is impossible");
+ }
+
+ for (unsigned long j = 0; j < a.number_of_nodes(); ++j)
+ {
+ if ((a.node(i).data == 1 && a.node(j).data == 1) ||
+ (a.node(i).data == 1 && a.node(j).data == 3) ||
+ (a.node(i).data == 3 && a.node(j).data == 1))
+ {
+ DLIB_TEST(a.has_edge(i,j) == true);
+ ++count;
+ }
+ else
+ {
+ DLIB_TEST(a.has_edge(i,j) == false);
+ }
+ }
+ }
+ DLIB_TEST_MSG(count == 3,count);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == true);
+ a.remove_edge(1,1);
+ DLIB_TEST(graph_contains_undirected_cycle(a) == false);
+
+ DLIB_TEST(b.number_of_nodes() == 4);
+ b.clear();
+ DLIB_TEST(b.number_of_nodes() == 0);
+
+
+ a.clear();
+
+ /*
+ 1 7
+ | / \
+ 2 6 0
+ \ / |
+ 3 /
+ / \ /
+ 4 5
+ */
+ a.set_number_of_nodes(8);
+ a.add_edge(1,2);
+ a.add_edge(2,3);
+ a.add_edge(3,4);
+ a.add_edge(3,5);
+ a.add_edge(3,6);
+ a.add_edge(6,7);
+ a.add_edge(7,0);
+ a.add_edge(0,5);
+
+ DLIB_TEST(graph_is_connected(a));
+
+ dlib::set<dlib::set<unsigned long>::compare_1b_c>::kernel_1b_c sos;
+
+ dlib::graph<dlib::set<unsigned long>::compare_1b_c, dlib::set<unsigned long>::compare_1b_c>::kernel_1a_c join_tree;
+ unsigned long temp;
+ triangulate_graph_and_find_cliques(a,sos);
+ DLIB_TEST(a.number_of_nodes() == 8);
+
+ create_join_tree(a, join_tree);
+ DLIB_TEST(join_tree.number_of_nodes() == 6);
+ DLIB_TEST(graph_is_connected(join_tree) == true);
+ DLIB_TEST(graph_contains_undirected_cycle(join_tree) == false);
+ DLIB_TEST(is_join_tree(a, join_tree));
+
+ // check old edges
+ DLIB_TEST(a.has_edge(1,2));
+ DLIB_TEST(a.has_edge(2,3));
+ DLIB_TEST(a.has_edge(3,4));
+ DLIB_TEST(a.has_edge(3,5));
+ DLIB_TEST(a.has_edge(3,6));
+ DLIB_TEST(a.has_edge(6,7));
+ DLIB_TEST(a.has_edge(7,0));
+ DLIB_TEST(a.has_edge(0,5));
+
+ DLIB_TEST(graph_is_connected(a));
+
+ DLIB_TEST(sos.size() == 6);
+
+
+ temp = 1; s.add(temp);
+ temp = 2; s.add(temp);
+ DLIB_TEST(sos.is_member(s));
+ s.clear();
+ temp = 2; s.add(temp);
+ temp = 3; s.add(temp);
+ DLIB_TEST(sos.is_member(s));
+ s.clear();
+ temp = 4; s.add(temp);
+ temp = 3; s.add(temp);
+ DLIB_TEST(sos.is_member(s));
+
+ sos.reset();
+ while (sos.move_next())
+ {
+ DLIB_TEST(is_clique(a, sos.element()));
+ DLIB_TEST(is_maximal_clique(a, sos.element()));
+ }
+
+ }
+
+
+ void test_copy()
+ {
+ {
+ graph<int,int>::kernel_1a_c a,b;
+
+ a.set_number_of_nodes(3);
+ a.node(0).data = 1;
+ a.node(1).data = 2;
+ a.node(2).data = 3;
+ a.add_edge(0,1);
+ a.add_edge(0,2);
+ edge(a,0,1) = 4;
+ edge(a,0,2) = 5;
+
+ a.add_edge(0,0);
+ edge(a,0,0) = 9;
+ copy_graph(a, b);
+
+ DLIB_TEST(b.number_of_nodes() == 3);
+ DLIB_TEST(b.node(0).data == 1);
+ DLIB_TEST(b.node(1).data == 2);
+ DLIB_TEST(b.node(2).data == 3);
+ DLIB_TEST(edge(b,0,1) == 4);
+ DLIB_TEST(edge(b,0,2) == 5);
+ DLIB_TEST(edge(b,0,0) == 9);
+ }
+ {
+ graph<int,int>::kernel_1a_c a,b;
+
+ a.set_number_of_nodes(4);
+ a.node(0).data = 1;
+ a.node(1).data = 2;
+ a.node(2).data = 3;
+ a.node(3).data = 8;
+ a.add_edge(0,1);
+ a.add_edge(0,2);
+ a.add_edge(2,3);
+ edge(a,0,1) = 4;
+ edge(a,0,2) = 5;
+ edge(a,2,3) = 6;
+
+ copy_graph(a, b);
+
+ DLIB_TEST(b.number_of_nodes() == 4);
+ DLIB_TEST(b.node(0).data == 1);
+ DLIB_TEST(b.node(1).data == 2);
+ DLIB_TEST(b.node(2).data == 3);
+ DLIB_TEST(b.node(3).data == 8);
+ DLIB_TEST(edge(b,0,1) == 4);
+ DLIB_TEST(edge(b,0,2) == 5);
+ DLIB_TEST(edge(b,2,3) == 6);
+ }
+ }
+
+
+
+ class graph_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a test for the graph object. When it is constructed
+ it adds itself into the testing framework. The command line switch is
+ specified as test_directed_graph by passing that string to the tester constructor.
+ !*/
+ public:
+ graph_tester (
+ ) :
+ tester ("test_graph",
+ "Runs tests on the graph component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a_c";
+ graph_test<graph<int>::kernel_1a_c>();
+
+ dlog << LINFO << "testing kernel_1a";
+ graph_test<graph<int>::kernel_1a>();
+
+ test_copy();
+ }
+ } a;
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/graph_cuts.cpp b/ml/dlib/dlib/test/graph_cuts.cpp
new file mode 100644
index 000000000..43ba35c16
--- /dev/null
+++ b/ml/dlib/dlib/test/graph_cuts.cpp
@@ -0,0 +1,1217 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/graph_cuts.h>
+#include <dlib/graph_utils.h>
+#include <dlib/directed_graph.h>
+#include <dlib/graph.h>
+#include <dlib/rand.h>
+#include <dlib/hash.h>
+#include <dlib/image_transforms.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+
+ logger dlog("test.graph_cuts");
+
+// ----------------------------------------------------------------------------------------
+
+ class dense_potts_problem
+ {
+ public:
+ typedef double value_type;
+ private:
+
+ matrix<value_type,0,1> factors1;
+ matrix<value_type> factors2;
+ matrix<node_label,0,1> labels;
+ public:
+
+ dense_potts_problem (
+ unsigned long num_nodes,
+ dlib::rand& rnd
+ )
+ {
+ factors1 = -7*(randm(num_nodes, 1, rnd)-0.5);
+ factors2 = make_symmetric(randm(num_nodes, num_nodes, rnd) > 0.5);
+ labels.set_size(num_nodes);
+ labels = FREE_NODE;
+ }
+
+ unsigned long number_of_nodes (
+ ) const { return factors1.nr(); }
+
+ unsigned long number_of_neighbors (
+ unsigned long // idx
+ ) const { return number_of_nodes()-1; }
+
+ unsigned long get_neighbor_idx (
+ unsigned long node_id1,
+ unsigned long node_id2
+ ) const
+ {
+ if (node_id2 < node_id1)
+ return node_id2;
+ else
+ return node_id2-1;
+ }
+
+ unsigned long get_neighbor (
+ unsigned long node_id,
+ unsigned long idx
+ ) const
+ {
+ DLIB_TEST(node_id < number_of_nodes());
+ DLIB_TEST(idx < number_of_neighbors(node_id));
+ if (idx < node_id)
+ return idx;
+ else
+ return idx+1;
+ }
+
+ void set_label (
+ const unsigned long& idx,
+ node_label value
+ )
+ {
+ labels(idx) = value;
+ }
+
+ node_label get_label (
+ const unsigned long& idx
+ ) const
+ {
+ return labels(idx);
+ }
+
+
+ value_type factor_value (unsigned long idx) const
+ {
+ DLIB_TEST(idx < number_of_nodes());
+
+ return factors1(idx);
+ }
+
+ value_type factor_value_disagreement (unsigned long idx1, unsigned long idx2) const
+ {
+ DLIB_TEST(idx1 != idx2);
+ DLIB_TEST(idx1 < number_of_nodes());
+ DLIB_TEST(idx2 < number_of_nodes());
+ DLIB_TEST(get_neighbor_idx(idx1,idx2) < number_of_neighbors(idx1));
+ DLIB_TEST(get_neighbor_idx(idx2,idx1) < number_of_neighbors(idx2));
+
+ return factors2(idx1, idx2);
+ }
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ class image_potts_problem
+ {
+ public:
+ typedef double value_type;
+ const static unsigned long max_number_of_neighbors = 4;
+ private:
+
+ matrix<value_type,0,1> factors1;
+ matrix<value_type> factors2;
+ matrix<node_label,0,1> labels;
+ long nr;
+ long nc;
+ rectangle rect, inner_rect;
+ mutable long count;
+ public:
+
+ image_potts_problem (
+ long nr_,
+ long nc_,
+ dlib::rand& rnd
+ ) : nr(nr_), nc(nc_)
+ {
+ rect = rectangle(0,0,nc-1,nr-1);
+ inner_rect = shrink_rect(rect,1);
+ const unsigned long num_nodes = nr*nc;
+ factors1 = -7*(randm(num_nodes, 1, rnd));
+ factors2 = randm(num_nodes, 4, rnd) > 0.5;
+
+ //factors1 = 0;
+ //set_rowm(factors1, range(0, factors1.nr()/2)) = -1;
+
+ labels.set_size(num_nodes);
+ labels = FREE_NODE;
+
+ count = 0;
+ }
+
+ ~image_potts_problem()
+ {
+ dlog << LTRACE << "interface calls: " << count;
+ dlog << LTRACE << "labels hash: "<< murmur_hash3_128bit(&labels(0), labels.size()*sizeof(labels(0)), 0).first;
+ }
+
+ unsigned long number_of_nodes (
+ ) const { return factors1.nr(); }
+
+ unsigned long number_of_neighbors (
+ unsigned long idx
+ ) const
+ {
+ ++count;
+ const point& p = get_loc(idx);
+ if (inner_rect.contains(p))
+ return 4;
+ else if (p == rect.tl_corner() ||
+ p == rect.bl_corner() ||
+ p == rect.tr_corner() ||
+ p == rect.br_corner() )
+ return 2;
+ else
+ return 3;
+ }
+
+ unsigned long get_neighbor_idx (
+ long node_id1,
+ long node_id2
+ ) const
+ {
+ ++count;
+ const point& p = get_loc(node_id1);
+ long ret = 0;
+ if (rect.contains(p + point(1,0)))
+ {
+ if (node_id2-node_id1 == 1)
+ return ret;
+ ++ret;
+ }
+
+ if (rect.contains(p - point(1,0)))
+ {
+ if (node_id2-node_id1 == -1)
+ return ret;
+ ++ret;
+ }
+
+ if (rect.contains(p + point(0,1)))
+ {
+ if (node_id2-node_id1 == nc)
+ return ret;
+ ++ret;
+ }
+
+ return ret;
+ }
+
+ unsigned long get_neighbor (
+ long node_id,
+ long idx
+ ) const
+ {
+ ++count;
+ const point& p = get_loc(node_id);
+ if (rect.contains(p + point(1,0)))
+ {
+ if (idx == 0)
+ return node_id+1;
+ --idx;
+ }
+
+ if (rect.contains(p - point(1,0)))
+ {
+ if (idx == 0)
+ return node_id-1;
+ --idx;
+ }
+
+ if (rect.contains(p + point(0,1)))
+ {
+ if (idx == 0)
+ return node_id+nc;
+ --idx;
+ }
+
+ return node_id-nc;
+ }
+
+ void set_label (
+ const unsigned long& idx,
+ node_label value
+ )
+ {
+ ++count;
+ labels(idx) = value;
+ }
+
+ node_label get_label (
+ const unsigned long& idx
+ ) const
+ {
+ ++count;
+ return labels(idx);
+ }
+
+ value_type factor_value (unsigned long idx) const
+ {
+ ++count;
+ DLIB_TEST(idx < (unsigned long)number_of_nodes());
+
+ return factors1(idx);
+ }
+
+ value_type factor_value_disagreement (unsigned long idx1, unsigned long idx2) const
+ {
+ ++count;
+ DLIB_TEST(idx1 != idx2);
+ DLIB_TEST(idx1 < (unsigned long)number_of_nodes());
+ DLIB_TEST(idx2 < (unsigned long)number_of_nodes());
+
+ // make this function symmetric
+ if (idx1 > idx2)
+ swap(idx1,idx2);
+
+
+ DLIB_TEST(get_neighbor(idx1, get_neighbor_idx(idx1, idx2)) == idx2);
+ DLIB_TEST(get_neighbor(idx2, get_neighbor_idx(idx2, idx1)) == idx1);
+
+ // the neighbor relationship better be symmetric
+ DLIB_TEST(get_neighbor_idx(idx1,idx2) < number_of_neighbors(idx1));
+ DLIB_TEST_MSG(get_neighbor_idx(idx2,idx1) < number_of_neighbors(idx2),
+ "\n idx1: "<< idx1 <<
+ "\n idx2: "<< idx2 <<
+ "\n get_neighbor_idx(idx2,idx1): "<< get_neighbor_idx(idx2,idx1) <<
+ "\n number_of_neighbors(idx2): " << number_of_neighbors(idx2) <<
+ "\n nr: "<< nr <<
+ "\n nc: "<< nc
+ );
+
+ return factors2(idx1, get_neighbor_idx(idx1,idx2));
+ }
+
+ private:
+ point get_loc (
+ const unsigned long& idx
+ ) const
+ {
+ return point(idx%nc, idx/nc);
+ }
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename potts_model>
+ void brute_force_potts_model (
+ potts_model& g
+ )
+ {
+ potts_model m(g);
+
+ const unsigned long num = (unsigned long)std::pow(2.0, (double)m.number_of_nodes());
+
+ double best_score = -std::numeric_limits<double>::infinity();
+ for (unsigned long i = 0; i < num; ++i)
+ {
+ for (unsigned long j = 0; j < m.number_of_nodes(); ++j)
+ {
+ unsigned long T = (1)<<j;
+ T = (T&i);
+ if (T != 0)
+ m.set_label(j,SINK_CUT);
+ else
+ m.set_label(j,SOURCE_CUT);
+ }
+
+
+ double score = potts_model_score(m);
+ if (score > best_score)
+ {
+ best_score = score;
+ g = m;
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename graph_type>
+ void brute_force_potts_model_on_graph (
+ const graph_type& g,
+ std::vector<node_label>& labels_
+ )
+ {
+ std::vector<node_label> labels;
+ labels.resize(g.number_of_nodes());
+
+ const unsigned long num = (unsigned long)std::pow(2.0, (double)g.number_of_nodes());
+
+ double best_score = -std::numeric_limits<double>::infinity();
+ for (unsigned long i = 0; i < num; ++i)
+ {
+ for (unsigned long j = 0; j < g.number_of_nodes(); ++j)
+ {
+ unsigned long T = (1)<<j;
+ T = (T&i);
+ if (T != 0)
+ labels[j] = SINK_CUT;
+ else
+ labels[j] = SOURCE_CUT;
+ }
+
+
+ double score = potts_model_score(g,labels);
+ if (score > best_score)
+ {
+ best_score = score;
+ labels_ = labels;
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename graph_type>
+ void make_random_undirected_graph(
+ dlib::rand& rnd,
+ graph_type& g
+ )
+ {
+ typedef typename graph_type::edge_type edge_weight_type;
+ g.clear();
+ const unsigned int num_nodes = rnd.get_random_32bit_number()%8;
+ g.set_number_of_nodes(num_nodes);
+
+ const unsigned int num_edges = static_cast<unsigned int>(num_nodes*(num_nodes-1)/2*rnd.get_random_double() + 0.5);
+
+ // add the right number of randomly selected edges
+ unsigned int count = 0;
+ while (count < num_edges)
+ {
+ unsigned long i = rnd.get_random_32bit_number()%g.number_of_nodes();
+ unsigned long j = rnd.get_random_32bit_number()%g.number_of_nodes();
+ if (i != j && g.has_edge(i, j) == false)
+ {
+ ++count;
+ g.add_edge(i, j);
+ edge(g, i, j) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ }
+ }
+
+ for (unsigned long i = 0; i < g.number_of_nodes(); ++i)
+ {
+ g.node(i).data = static_cast<edge_weight_type>(rnd.get_random_gaussian()*200);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_graph_potts_model(
+ dlib::rand& rnd
+ )
+ {
+ using namespace std;
+ double brute_force_score;
+ double graph_cut_score;
+
+ graph<double,double>::kernel_1a_c temp;
+ make_random_undirected_graph(rnd,temp);
+
+ {
+ std::vector<node_label> labels;
+
+ brute_force_potts_model_on_graph(temp, labels);
+
+ for (unsigned long i = 0; i < temp.number_of_nodes(); ++i)
+ {
+ dlog << LTRACE << "node " << i << ": "<< (int)labels[i];
+ }
+
+ brute_force_score = potts_model_score(temp, labels);
+ dlog << LTRACE << "brute force score: "<< brute_force_score;
+ }
+ dlog << LTRACE << "******************";
+
+ {
+ std::vector<node_label> labels;
+ find_max_factor_graph_potts(temp, labels);
+ DLIB_TEST(temp.number_of_nodes() == labels.size());
+
+ for (unsigned long i = 0; i < temp.number_of_nodes(); ++i)
+ {
+ dlog << LTRACE << "node " << i << ": "<< (int)labels[i];
+ }
+ graph_cut_score = potts_model_score(temp, labels);
+ dlog << LTRACE << "graph cut score: "<< graph_cut_score;
+ }
+
+ DLIB_TEST_MSG(graph_cut_score == brute_force_score, std::abs(graph_cut_score - brute_force_score));
+
+ dlog << LTRACE << "##################";
+ dlog << LTRACE << "##################";
+ dlog << LTRACE << "##################";
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename potts_prob>
+ void impl_test_potts_model (
+ potts_prob& p
+ )
+ {
+ using namespace std;
+ double brute_force_score;
+ double graph_cut_score;
+
+ {
+ potts_prob temp(p);
+ brute_force_potts_model(temp);
+
+ for (unsigned long i = 0; i < temp.number_of_nodes(); ++i)
+ {
+ dlog << LTRACE << "node " << i << ": "<< (int)temp.get_label(i);
+ }
+ brute_force_score = potts_model_score(temp);
+ dlog << LTRACE << "brute force score: "<< brute_force_score;
+ }
+ dlog << LTRACE << "******************";
+
+ {
+ potts_prob temp(p);
+ find_max_factor_graph_potts(temp);
+
+ for (unsigned long i = 0; i < temp.number_of_nodes(); ++i)
+ {
+ dlog << LTRACE << "node " << i << ": "<< (int)temp.get_label(i);
+ }
+ graph_cut_score = potts_model_score(temp);
+ dlog << LTRACE << "graph cut score: "<< graph_cut_score;
+ }
+
+ DLIB_TEST_MSG(graph_cut_score == brute_force_score, std::abs(graph_cut_score - brute_force_score));
+
+ dlog << LTRACE << "##################";
+ dlog << LTRACE << "##################";
+ dlog << LTRACE << "##################";
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// BASIC MIN CUT STUFF
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ template <typename directed_graph>
+ void brute_force_min_cut (
+ directed_graph& g,
+ unsigned long source,
+ unsigned long sink
+ )
+ {
+ typedef typename directed_graph::edge_type edge_weight_type;
+ const unsigned long num = (unsigned long)std::pow(2.0, (double)g.number_of_nodes());
+
+ std::vector<node_label> best_cut(g.number_of_nodes(),FREE_NODE);
+
+ edge_weight_type best_score = std::numeric_limits<edge_weight_type>::max();
+ for (unsigned long i = 0; i < num; ++i)
+ {
+ for (unsigned long j = 0; j < g.number_of_nodes(); ++j)
+ {
+ unsigned long T = (1)<<j;
+ T = (T&i);
+ if (T != 0)
+ g.node(j).data = SINK_CUT;
+ else
+ g.node(j).data = SOURCE_CUT;
+ }
+
+ // ignore cuts that don't label the source or sink node the way we want.
+ if (g.node(source).data != SOURCE_CUT ||
+ g.node(sink).data != SINK_CUT)
+ continue;
+
+ edge_weight_type score = graph_cut_score(g);
+ if (score < best_score)
+ {
+ best_score = score;
+ for (unsigned long j = 0; j < g.number_of_nodes(); ++j)
+ best_cut[j] = g.node(j).data;
+ }
+ }
+
+ for (unsigned long j = 0; j < g.number_of_nodes(); ++j)
+ g.node(j).data = best_cut[j];
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename directed_graph>
+ void print_graph(
+ const directed_graph& g
+ )
+ {
+ using namespace std;
+ dlog << LTRACE << "number of nodes: "<< g.number_of_nodes();
+ for (unsigned long i = 0; i < g.number_of_nodes(); ++i)
+ {
+ for (unsigned long n = 0; n < g.node(i).number_of_children(); ++n)
+ dlog << LTRACE << i << " -(" << g.node(i).child_edge(n) << ")-> " << g.node(i).child(n).index();
+ }
+ }
+
+ template <typename directed_graph>
+ void copy_edge_weights (
+ directed_graph& dest,
+ const directed_graph& src
+ )
+ {
+ for (unsigned long i = 0; i < src.number_of_nodes(); ++i)
+ {
+ for (unsigned long n = 0; n < src.node(i).number_of_children(); ++n)
+ {
+ dest.node(i).child_edge(n) = src.node(i).child_edge(n);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename graph_type>
+ void pick_random_source_and_sink (
+ dlib::rand& rnd,
+ const graph_type& g,
+ unsigned long& source,
+ unsigned long& sink
+ )
+ {
+ source = rnd.get_random_32bit_number()%g.number_of_nodes();
+ sink = rnd.get_random_32bit_number()%g.number_of_nodes();
+ while (sink == source)
+ sink = rnd.get_random_32bit_number()%g.number_of_nodes();
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename dgraph_type>
+ void make_random_graph(
+ dlib::rand& rnd,
+ dgraph_type& g,
+ unsigned long& source,
+ unsigned long& sink
+ )
+ {
+ typedef typename dgraph_type::edge_type edge_weight_type;
+ g.clear();
+ const unsigned int num_nodes = rnd.get_random_32bit_number()%7 + 2;
+ g.set_number_of_nodes(num_nodes);
+
+ const unsigned int num_edges = static_cast<unsigned int>(num_nodes*(num_nodes-1)/2*rnd.get_random_double() + 0.5);
+
+ // add the right number of randomly selected edges
+ unsigned int count = 0;
+ while (count < num_edges)
+ {
+ unsigned long parent = rnd.get_random_32bit_number()%g.number_of_nodes();
+ unsigned long child = rnd.get_random_32bit_number()%g.number_of_nodes();
+ if (parent != child && g.has_edge(parent, child) == false)
+ {
+ ++count;
+ g.add_edge(parent, child);
+ edge(g, parent, child) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+
+ // have to have edges both ways
+ swap(parent, child);
+ g.add_edge(parent, child);
+ edge(g, parent, child) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ }
+ }
+
+ pick_random_source_and_sink(rnd, g, source, sink);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename dgraph_type>
+ void make_random_chain_graph(
+ dlib::rand& rnd,
+ dgraph_type& g,
+ unsigned long& source,
+ unsigned long& sink
+ )
+ {
+ typedef typename dgraph_type::edge_type edge_weight_type;
+ g.clear();
+ const unsigned int num_nodes = rnd.get_random_32bit_number()%7 + 2;
+ g.set_number_of_nodes(num_nodes);
+
+ for (unsigned long i = 1; i < g.number_of_nodes(); ++i)
+ {
+ g.add_edge(i,i-1);
+ g.add_edge(i-1,i);
+ edge(g, i, i-1) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ edge(g, i-1, i) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ }
+
+ pick_random_source_and_sink(rnd, g, source, sink);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename dgraph_type>
+ void make_random_grid_graph(
+ dlib::rand& rnd,
+ dgraph_type& g,
+ unsigned long& source,
+ unsigned long& sink
+ )
+ /*!
+ ensures
+ - makes a grid graph like the kind used for potts models.
+ !*/
+ {
+ typedef typename dgraph_type::edge_type edge_weight_type;
+ g.clear();
+ const long nr = rnd.get_random_32bit_number()%2 + 2;
+ const long nc = rnd.get_random_32bit_number()%2 + 2;
+ g.set_number_of_nodes(nr*nc+2);
+
+ const rectangle rect(0,0,nc-1,nr-1);
+ for (long r = 0; r < nr; ++r)
+ {
+ for (long c = 0; c < nc; ++c)
+ {
+ const point p(c,r);
+ const unsigned long i = p.y()*nc + p.x();
+
+ const point n2(c-1,r);
+ if (rect.contains(n2))
+ {
+ const unsigned long j = n2.y()*nc + n2.x();
+ g.add_edge(i,j);
+ g.add_edge(j,i);
+ edge(g,i,j) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ edge(g,j,i) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ }
+
+ const point n4(c,r-1);
+ if (rect.contains(n4))
+ {
+ const unsigned long j = n4.y()*nc + n4.x();
+ g.add_edge(i,j);
+ g.add_edge(j,i);
+ edge(g,i,j) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ edge(g,j,i) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ }
+ }
+ }
+
+ // use the last two nodes as source and sink. Also connect them to all the other nodes.
+ source = g.number_of_nodes()-1;
+ sink = g.number_of_nodes()-2;
+ for (unsigned long i = 0; i < g.number_of_nodes()-2; ++i)
+ {
+ g.add_edge(i,source);
+ g.add_edge(source,i);
+ g.add_edge(i,sink);
+ g.add_edge(sink,i);
+
+ edge(g,i,source) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ edge(g,source,i) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ edge(g,i,sink) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ edge(g,sink,i) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename min_cut, typename dgraph_type>
+ void run_test_on_graphs (
+ const min_cut& mc,
+ dgraph_type& g1,
+ dgraph_type& g2,
+ unsigned long source,
+ unsigned long sink
+ )
+ {
+ typedef typename dgraph_type::edge_type edge_weight_type;
+ using namespace std;
+
+
+ dlog << LTRACE << "number of nodes: "<< g1.number_of_nodes();
+ dlog << LTRACE << "is graph connected: "<< graph_is_connected(g1);
+ dlog << LTRACE << "has self loops: "<< graph_contains_length_one_cycle(g1);
+ dlog << LTRACE << "SOURCE_CUT: " << source;
+ dlog << LTRACE << "SINK_CUT: " << sink;
+ mc(g1, source, sink);
+ brute_force_min_cut(g2, source, sink);
+
+ print_graph(g1);
+
+ // make sure the flow residuals are 0 at the cut locations
+ for (unsigned long i = 0; i < g1.number_of_nodes(); ++i)
+ {
+ for (unsigned long j = 0; j < g1.node(i).number_of_children(); ++j)
+ {
+ if ((g1.node(i).data == SOURCE_CUT && g1.node(i).child(j).data != SOURCE_CUT) ||
+ (g1.node(i).data != SINK_CUT && g1.node(i).child(j).data == SINK_CUT)
+ )
+ {
+ DLIB_TEST_MSG(g1.node(i).child_edge(j) == 0, g1.node(i).child_edge(j));
+ }
+ }
+ }
+
+ // copy the edge weights from g2 back to g1 so we can compute cut scores
+ copy_edge_weights(g1, g2);
+
+ DLIB_TEST(g1.number_of_nodes() == g2.number_of_nodes());
+ for (unsigned long i = 0; i < g1.number_of_nodes(); ++i)
+ {
+ dlog << LTRACE << "node " << i << ": " << (int)g1.node(i).data << ", " << (int)g2.node(i).data;
+ if (g1.node(i).data != g2.node(i).data)
+ {
+ edge_weight_type cut_score = graph_cut_score(g1);
+ edge_weight_type brute_force_score = graph_cut_score(g2);
+ dlog << LTRACE << "graph cut score: "<< cut_score;
+ dlog << LTRACE << "brute force score: "<< brute_force_score;
+
+ if (brute_force_score != cut_score)
+ print_graph(g1);
+ DLIB_TEST_MSG(brute_force_score == cut_score,std::abs(brute_force_score-cut_score));
+ }
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename min_cut, typename edge_weight_type>
+ void test_graph_cuts(dlib::rand& rnd)
+ {
+ typedef typename dlib::directed_graph<node_label, edge_weight_type>::kernel_1a_c dgraph_type;
+ // we will create two identical graphs.
+ dgraph_type g1, g2;
+ min_cut mc;
+
+ unsigned long source, sink;
+
+ dlib::rand rnd_copy(rnd);
+ make_random_graph(rnd,g1, source, sink);
+ make_random_graph(rnd_copy,g2, source, sink);
+ run_test_on_graphs(mc, g1, g2, source, sink);
+
+ rnd_copy = rnd;
+ make_random_grid_graph(rnd,g1, source, sink);
+ make_random_grid_graph(rnd_copy,g2, source, sink);
+ run_test_on_graphs(mc, g1, g2, source, sink);
+
+ rnd_copy = rnd;
+ make_random_chain_graph(rnd,g1, source, sink);
+ make_random_chain_graph(rnd_copy,g2, source, sink);
+ run_test_on_graphs(mc, g1, g2, source, sink);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_potts_grid_problem
+ {
+ public:
+ test_potts_grid_problem(int seed_) :seed(seed_){}
+ int seed;
+
+ long nr() const { return 3;}
+ long nc() const { return 3;}
+
+ typedef double value_type;
+
+ value_type factor_value(unsigned long idx) const
+ {
+ // Copy idx into a char buffer to avoid warnings about violation of strict aliasing
+ // rules when murmur_hash3() gets inlined into this function.
+ char buf[sizeof(idx)];
+ memcpy(buf,&idx,sizeof(idx));
+ // now hash the buffer rather than idx.
+ return ((double)murmur_hash3(buf, sizeof(buf), seed) - std::numeric_limits<uint32>::max()/2.0)/1000.0;
+ }
+
+ value_type factor_value_disagreement(unsigned long idx1, unsigned long idx2) const
+ {
+ return std::abs(factor_value(idx1+idx2)/10.0);
+ }
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename prob_type>
+ void brute_force_potts_grid_problem(
+ const prob_type& prob,
+ array2d<unsigned char>& labels
+ )
+ {
+ const unsigned long num = (unsigned long)std::pow(2.0, (double)prob.nr()*prob.nc());
+
+ array2d<unsigned char> temp(prob.nr(), prob.nc());
+ unsigned char* data = &temp[0][0];
+
+ double best_score = -std::numeric_limits<double>::infinity();
+ for (unsigned long i = 0; i < num; ++i)
+ {
+ for (unsigned long j = 0; j < temp.size(); ++j)
+ {
+ unsigned long T = (1)<<j;
+ T = (T&i);
+ if (T != 0)
+ *(data + j) = SINK_CUT;
+ else
+ *(data + j) = SOURCE_CUT;
+ }
+
+
+ double score = potts_model_score(prob, temp);
+ if (score > best_score)
+ {
+ best_score = score;
+ assign_image(labels, temp);
+ }
+ }
+ }
+
+ void test_inf()
+ {
+ graph<double,double>::kernel_1a_c g;
+ g.set_number_of_nodes(4);
+ g.add_edge(0,1);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+
+ g.node(0).data = std::numeric_limits<double>::infinity();
+ g.node(1).data = -std::numeric_limits<double>::infinity();
+ g.node(2).data = std::numeric_limits<double>::infinity();
+ g.node(3).data = -std::numeric_limits<double>::infinity();
+
+ edge(g,0,1) = 1;
+ edge(g,1,2) = 1;
+ edge(g,2,3) = 1;
+ edge(g,3,0) = 1;
+
+ std::vector<node_label> labels;
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] != 0);
+ DLIB_TEST(labels[1] == 0);
+ DLIB_TEST(labels[2] != 0);
+ DLIB_TEST(labels[3] == 0);
+
+ // --------------------------
+
+ g.node(0).data = std::numeric_limits<double>::infinity();
+ g.node(1).data = 0;
+ g.node(2).data = 0;
+ g.node(3).data = -3;
+
+ edge(g,0,1) = 1;
+ edge(g,1,2) = 1;
+ edge(g,2,3) = 1;
+ edge(g,3,0) = 1;
+
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] != 0);
+ DLIB_TEST(labels[1] != 0);
+ DLIB_TEST(labels[2] != 0);
+ DLIB_TEST(labels[3] == 0);
+
+ // --------------------------
+
+ g.node(0).data = std::numeric_limits<double>::infinity();
+ g.node(1).data = 0;
+ g.node(2).data = 0;
+ g.node(3).data = -0.1;
+
+ edge(g,0,1) = 1;
+ edge(g,1,2) = 1;
+ edge(g,2,3) = 1;
+ edge(g,3,0) = 1;
+
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] != 0);
+ DLIB_TEST(labels[1] != 0);
+ DLIB_TEST(labels[2] != 0);
+ DLIB_TEST(labels[3] != 0);
+
+ // --------------------------
+
+ g.node(0).data = std::numeric_limits<double>::infinity();
+ g.node(1).data = 0;
+ g.node(2).data = 0;
+ g.node(3).data = -0.1;
+
+ edge(g,0,1) = 1;
+ edge(g,1,2) = 1;
+ edge(g,2,3) = 0;
+ edge(g,3,0) = 0;
+
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] != 0);
+ DLIB_TEST(labels[1] != 0);
+ DLIB_TEST(labels[2] != 0);
+ DLIB_TEST(labels[3] == 0);
+
+ // --------------------------
+
+ g.node(0).data = -std::numeric_limits<double>::infinity();
+ g.node(1).data = 0;
+ g.node(2).data = 0;
+ g.node(3).data = 0.1;
+
+ edge(g,0,1) = 1;
+ edge(g,1,2) = 1;
+ edge(g,2,3) = 0;
+ edge(g,3,0) = 0;
+
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(labels[1] == 0);
+ DLIB_TEST(labels[2] == 0);
+ DLIB_TEST(labels[3] != 0);
+
+ // --------------------------
+
+ g.node(0).data = -std::numeric_limits<double>::infinity();
+ g.node(1).data = std::numeric_limits<double>::infinity();
+ g.node(2).data = 0;
+ g.node(3).data = 0.1;
+
+ edge(g,0,1) = 1;
+ edge(g,1,2) = 1;
+ edge(g,2,3) = 0;
+ edge(g,3,0) = 0;
+
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(labels[1] != 0);
+ DLIB_TEST(labels[2] != 0);
+ DLIB_TEST(labels[3] != 0);
+
+ // --------------------------
+
+ g.node(0).data = -10;
+ g.node(1).data = std::numeric_limits<double>::infinity();
+ g.node(2).data = 0;
+ g.node(3).data = 0.1;
+
+ edge(g,0,1) = std::numeric_limits<double>::infinity();
+ edge(g,1,2) = std::numeric_limits<double>::infinity();
+ edge(g,2,3) = std::numeric_limits<double>::infinity();
+ edge(g,3,0) = std::numeric_limits<double>::infinity();
+
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] != 0);
+ DLIB_TEST(labels[1] != 0);
+ DLIB_TEST(labels[2] != 0);
+ DLIB_TEST(labels[3] != 0);
+
+ // --------------------------
+
+ g.node(0).data = 10;
+ g.node(1).data = -std::numeric_limits<double>::infinity();
+ g.node(2).data = 20.05;
+ g.node(3).data = -0.1;
+
+ edge(g,0,1) = std::numeric_limits<double>::infinity();
+ edge(g,1,2) = 10;
+ edge(g,2,3) = std::numeric_limits<double>::infinity();
+ edge(g,3,0) = 10;
+
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(labels[1] == 0);
+ DLIB_TEST(labels[2] == 0);
+ DLIB_TEST(labels[3] == 0);
+
+ // --------------------------
+
+ g.node(0).data = 10;
+ g.node(1).data = -std::numeric_limits<double>::infinity();
+ g.node(2).data = 20.2;
+ g.node(3).data = -0.1;
+
+ edge(g,0,1) = std::numeric_limits<double>::infinity();
+ edge(g,1,2) = 10;
+ edge(g,2,3) = std::numeric_limits<double>::infinity();
+ edge(g,3,0) = 10;
+
+ find_max_factor_graph_potts(g, labels);
+
+ DLIB_TEST(labels[0] == 0);
+ DLIB_TEST(labels[1] == 0);
+ DLIB_TEST(labels[2] != 0);
+ DLIB_TEST(labels[3] != 0);
+ }
+
+ struct potts_pair_image_model
+ {
+ typedef double value_type;
+
+ template <typename pixel_type1, typename pixel_type2>
+ value_type factor_value (
+ const pixel_type1& ,
+ const pixel_type2& v2
+ ) const
+ {
+ return v2;
+ }
+
+ template <typename pixel_type>
+ value_type factor_value_disagreement (
+ const pixel_type& v1,
+ const pixel_type& v2
+ ) const
+ {
+ if (v1 == v2)
+ return 10;
+ else
+ return 0;
+ }
+ };
+
+ void test_potts_pair_grid()
+ {
+ array2d<int> img1(40,40);
+ array2d<double> img2(40,40);
+
+ assign_all_pixels(img1, -1);
+ assign_all_pixels(img2, -1);
+
+ img1[4][4] = 1000;
+
+ img2[4][3] = 1;
+ img2[4][4] = 1;
+ img2[4][5] = 1;
+ img2[3][3] = 1;
+ img2[3][4] = 1;
+ img2[3][5] = 1;
+ img2[5][3] = 1;
+ img2[5][4] = 1;
+ img2[5][5] = 1;
+
+ array2d<unsigned char> labels;
+ find_max_factor_graph_potts(make_potts_grid_problem(potts_pair_image_model(),img2,img1), labels);
+
+ dlog << LINFO << "num true labels: " << sum(matrix_cast<int>(mat(labels)!=0));
+ DLIB_TEST(sum(matrix_cast<int>(mat(labels)!=0)) == 9);
+ DLIB_TEST(sum(matrix_cast<int>(mat(labels)==0)) == (int)img1.size()-9);
+
+ DLIB_TEST(labels[4][3] != 0);
+ DLIB_TEST(labels[4][4] != 0);
+ DLIB_TEST(labels[4][5] != 0);
+ DLIB_TEST(labels[3][3] != 0);
+ DLIB_TEST(labels[3][4] != 0);
+ DLIB_TEST(labels[3][5] != 0);
+ DLIB_TEST(labels[5][3] != 0);
+ DLIB_TEST(labels[5][4] != 0);
+ DLIB_TEST(labels[5][5] != 0);
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ class graph_cuts_tester : public tester
+ {
+ public:
+ graph_cuts_tester (
+ ) :
+ tester ("test_graph_cuts",
+ "Runs tests on the graph cuts tools.")
+ {}
+
+ dlib::rand rnd;
+
+ void perform_test (
+ )
+ {
+ test_potts_pair_grid();
+ test_inf();
+
+ for (int i = 0; i < 500; ++i)
+ {
+ array2d<unsigned char> labels, brute_labels;
+ test_potts_grid_problem prob(i);
+ find_max_factor_graph_potts(prob, labels);
+ brute_force_potts_grid_problem(prob, brute_labels);
+
+ DLIB_TEST(labels.nr() == brute_labels.nr());
+ DLIB_TEST(labels.nc() == brute_labels.nc());
+ for (long r = 0; r < labels.nr(); ++r)
+ {
+ for (long c = 0; c < labels.nc(); ++c)
+ {
+ bool normal = (labels[r][c] != 0);
+ bool brute = (brute_labels[r][c] != 0);
+ DLIB_TEST(normal == brute);
+ }
+ }
+ }
+
+ for (int i = 0; i < 1000; ++i)
+ {
+ print_spinner();
+ dlog << LTRACE << "test_grpah_cuts<short> iter: " << i;
+ test_graph_cuts<min_cut,short>(rnd);
+ print_spinner();
+ dlog << LTRACE << "test_grpah_cuts<double> iter: " << i;
+ test_graph_cuts<min_cut,double>(rnd);
+ }
+
+
+ for (int k = 0; k < 300; ++k)
+ {
+ dlog << LTRACE << "image_potts_problem iter " << k;
+ print_spinner();
+ image_potts_problem p(3,3, rnd);
+ impl_test_potts_model(p);
+ }
+ for (int k = 0; k < 300; ++k)
+ {
+ dlog << LTRACE << "dense_potts_problem iter " << k;
+ print_spinner();
+ dense_potts_problem p(6, rnd);
+ impl_test_potts_model(p);
+ }
+
+ for (int k = 0; k < 300; ++k)
+ {
+ dlog << LTRACE << "dense_potts_problem iter " << k;
+ print_spinner();
+ test_graph_potts_model(rnd);
+ }
+ }
+ } a;
+
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/graph_labeler.cpp b/ml/dlib/dlib/test/graph_labeler.cpp
new file mode 100644
index 000000000..112873896
--- /dev/null
+++ b/ml/dlib/dlib/test/graph_labeler.cpp
@@ -0,0 +1,472 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/svm_threaded.h>
+#include <dlib/data_io.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+
+
+ logger dlog("test.graph_cuts");
+
+
+ template <
+ typename graph_type,
+ typename samples_type,
+ typename labels_type
+ >
+ void make_data(
+ samples_type& samples,
+ labels_type& labels
+ )
+ {
+ //samples.clear();
+ //labels.clear();
+
+ std::vector<bool> label;
+ graph_type g;
+
+ // ---------------------------
+ g.set_number_of_nodes(4);
+ label.resize(g.number_of_nodes());
+ g.node(0).data = 0, 0, 1; label[0] = true;
+ g.node(1).data = 0, 0, 1; label[1] = true;
+ g.node(2).data = 0, 1, 0; label[2] = false;
+ g.node(3).data = 0, 1, 0; label[3] = false;
+
+ g.add_edge(0,1);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+
+ edge(g,0,1) = 1, 1;
+ edge(g,1,2) = 1, 1;
+ edge(g,2,3) = 1, 1;
+ edge(g,3,0) = 1, 1;
+ samples.push_back(g);
+ labels.push_back(label);
+ // ---------------------------
+
+ g.clear();
+ g.set_number_of_nodes(4);
+ label.resize(g.number_of_nodes());
+ g.node(0).data = 0, 0, 1; label[0] = true;
+ g.node(1).data = 0, 0, 0; label[1] = true;
+ g.node(2).data = 0, 1, 0; label[2] = false;
+ g.node(3).data = 0, 0, 0; label[3] = false;
+
+ g.add_edge(0,1);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+
+ edge(g,0,1) = 1, 0;
+ edge(g,1,2) = 0, 1;
+ edge(g,2,3) = 1, 0;
+ edge(g,3,0) = 0, 1;
+ samples.push_back(g);
+ labels.push_back(label);
+ // ---------------------------
+
+ g.clear();
+ g.set_number_of_nodes(4);
+ label.resize(g.number_of_nodes());
+ g.node(0).data = 0, 1, 0; label[0] = false;
+ g.node(1).data = 0, 1, 0; label[1] = false;
+ g.node(2).data = 0, 1, 0; label[2] = false;
+ g.node(3).data = 0, 0, 0; label[3] = false;
+
+ g.add_edge(0,1);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+
+ edge(g,0,1) = 1, 0;
+ edge(g,1,2) = 0, 1;
+ edge(g,2,3) = 1, 0;
+ edge(g,3,0) = 0, 1;
+ samples.push_back(g);
+ labels.push_back(label);
+ // ---------------------------
+ }
+
+
+
+
+ template <
+ typename graph_type,
+ typename samples_type,
+ typename labels_type
+ >
+ void make_data_sparse(
+ samples_type& samples,
+ labels_type& labels
+ )
+ {
+ //samples.clear();
+ //labels.clear();
+
+ std::vector<bool> label;
+ graph_type g;
+ typename graph_type::edge_type v;
+
+ // ---------------------------
+ g.set_number_of_nodes(4);
+ label.resize(g.number_of_nodes());
+ g.node(0).data[2] = 1; label[0] = true;
+ g.node(1).data[2] = 1; label[1] = true;
+ g.node(2).data[1] = 1; label[2] = false;
+ g.node(3).data[1] = 1; label[3] = false;
+
+ g.add_edge(0,1);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+ g.add_edge(3,1);
+
+ v[0] = 1; v[1] = 1;
+ edge(g,0,1) = v;
+ edge(g,1,2) = v;
+ edge(g,2,3) = v;
+ edge(g,3,0) = v;
+ samples.push_back(g);
+ labels.push_back(label);
+ // ---------------------------
+
+ g.clear();
+ g.set_number_of_nodes(5);
+ label.resize(g.number_of_nodes());
+ g.node(0).data[2] = 1; label[0] = true;
+ g.node(1).data[0] = 0; label[1] = true;
+ g.node(2).data[1] = 1; label[2] = false;
+ g.node(3).data[0] = 0; label[3] = false;
+ label[4] = true;
+
+ g.add_edge(0,1);
+ g.add_edge(1,4);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+
+ edge(g,0,1)[0] = 1;
+ edge(g,1,4)[0] = 1;
+ edge(g,1,2)[1] = 1;
+ edge(g,2,3)[0] = 1;
+ edge(g,3,0)[1] = 1;
+ samples.push_back(g);
+ labels.push_back(label);
+ // ---------------------------
+
+ g.clear();
+ g.set_number_of_nodes(4);
+ label.resize(g.number_of_nodes());
+ g.node(0).data[1] = 1; label[0] = false;
+ g.node(1).data[1] = 1; label[1] = false;
+ g.node(2).data[1] = 1; label[2] = false;
+ g.node(3).data[1] = 0; label[3] = false;
+
+ g.add_edge(0,1);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+
+ edge(g,0,1)[0] = 1;
+ edge(g,1,2)[1] = 1;
+ edge(g,2,3)[0] = 1;
+ edge(g,3,0)[1] = 1;
+ samples.push_back(g);
+ labels.push_back(label);
+ // ---------------------------
+ }
+
+
+
+
+
+
+ template <
+ typename graph_type,
+ typename samples_type,
+ typename labels_type
+ >
+ void make_data2(
+ samples_type& samples,
+ labels_type& labels
+ )
+ {
+ //samples.clear();
+ //labels.clear();
+
+ std::vector<bool> label;
+ graph_type g;
+
+ // ---------------------------
+ g.set_number_of_nodes(4);
+ label.resize(g.number_of_nodes());
+ g.node(0).data = 0, 0, 1; label[0] = true;
+ g.node(1).data = 0, 0, 1; label[1] = true;
+ g.node(2).data = 0, 1, 0; label[2] = false;
+ g.node(3).data = 0, 1, 0; label[3] = false;
+
+ g.add_edge(0,1);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+
+ edge(g,0,1) = 1, 1;
+ edge(g,1,2) = 1, 1;
+ edge(g,2,3) = 1, 1;
+ edge(g,3,0) = 1, 1;
+ samples.push_back(g);
+ labels.push_back(label);
+ // ---------------------------
+ }
+
+
+
+
+ template <
+ typename graph_type,
+ typename samples_type,
+ typename labels_type
+ >
+ void make_data2_sparse(
+ samples_type& samples,
+ labels_type& labels
+ )
+ {
+ //samples.clear();
+ //labels.clear();
+
+ std::vector<bool> label;
+ graph_type g;
+ typename graph_type::edge_type v;
+
+ // ---------------------------
+ g.set_number_of_nodes(4);
+ label.resize(g.number_of_nodes());
+ g.node(0).data[2] = 1; label[0] = true;
+ g.node(1).data[2] = 1; label[1] = true;
+ g.node(2).data[1] = 1; label[2] = false;
+ g.node(3).data[1] = 1; label[3] = false;
+
+ g.add_edge(0,1);
+ g.add_edge(1,2);
+ g.add_edge(2,3);
+ g.add_edge(3,0);
+
+ v[0] = 1; v[1] = 1;
+ edge(g,0,1) = v;
+ edge(g,1,2) = v;
+ edge(g,2,3) = v;
+ edge(g,3,0) = v;
+ samples.push_back(g);
+ labels.push_back(label);
+ // ---------------------------
+
+ }
+
+
+
+
+
+ template <
+ typename node_vector_type,
+ typename edge_vector_type,
+ typename vector_type,
+ typename graph_type
+ >
+ void test1(
+ const dlib::array<graph_type>& samples,
+ const std::vector<std::vector<bool> >& labels
+ )
+ {
+ dlog << LINFO << "begin test1()";
+
+ structural_graph_labeling_trainer<vector_type> trainer;
+ //trainer.be_verbose();
+ trainer.set_epsilon(1e-12);
+ graph_labeler<vector_type> labeler = trainer.train(samples, labels);
+
+
+ // test serialization code for the labeler.
+ std::ostringstream sout;
+ serialize(labeler, sout);
+ std::istringstream sin(sout.str());
+ labeler = graph_labeler<vector_type>();
+ deserialize(labeler, sin);
+
+ std::vector<bool> temp;
+ for (unsigned long k = 0; k < samples.size(); ++k)
+ {
+ temp = labeler(samples[k]);
+ for (unsigned long i = 0; i < temp.size(); ++i)
+ {
+ const bool true_label = (labels[k][i] != 0);
+ const bool pred_label = (temp[i] != 0);
+ DLIB_TEST(true_label == pred_label);
+ }
+ }
+
+ matrix<double> cv;
+
+ cv = test_graph_labeling_function(labeler, samples, labels);
+ DLIB_TEST(sum(cv) == 2);
+ cv = cross_validate_graph_labeling_trainer(trainer, samples, labels, 4);
+ DLIB_TEST(sum(cv) == 2);
+
+ dlog << LINFO << "edge weights: " << trans(sparse_to_dense(labeler.get_edge_weights()));
+ dlog << LINFO << "node weights: " << trans(sparse_to_dense(labeler.get_node_weights()));
+ }
+
+
+
+ class graph_labeling_tester : public tester
+ {
+ public:
+ graph_labeling_tester (
+ ) :
+ tester ("test_graph_labeling",
+ "Runs tests on the graph labeling component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ // test with dense vectors
+ {
+ typedef matrix<double,3,1> node_vector_type;
+ typedef matrix<double,2,1> edge_vector_type;
+ typedef matrix<double,0,1> vector_type;
+ typedef dlib::graph<node_vector_type, edge_vector_type>::kernel_1a_c graph_type;
+
+ dlib::array<graph_type> samples;
+ std::vector<std::vector<bool> > labels;
+
+ make_data<graph_type>(samples, labels);
+ make_data<graph_type>(samples, labels);
+ make_data<graph_type>(samples, labels);
+ make_data<graph_type>(samples, labels);
+
+
+ test1<node_vector_type,edge_vector_type,vector_type>(samples, labels);
+ }
+ print_spinner();
+ // test with dense vectors and sparse vectors together
+ {
+ typedef matrix<double,3,1> node_vector_type;
+ typedef matrix<double,2,1> edge_vector_type;
+ typedef std::map<unsigned long,double> vector_type;
+ typedef dlib::graph<node_vector_type, edge_vector_type>::kernel_1a_c graph_type;
+
+ dlib::array<graph_type> samples;
+ std::vector<std::vector<bool> > labels;
+
+ make_data<graph_type>(samples, labels);
+ make_data<graph_type>(samples, labels);
+ make_data<graph_type>(samples, labels);
+ make_data<graph_type>(samples, labels);
+
+
+ test1<node_vector_type,edge_vector_type,vector_type>(samples, labels);
+ }
+ print_spinner();
+ // test with sparse vectors
+ {
+ typedef std::vector<std::pair<unsigned long,double> > vector_type;
+ typedef std::map<unsigned long, double> edge_vector_type;
+ typedef std::map<unsigned long, double> node_vector_type;
+ typedef dlib::graph<node_vector_type, edge_vector_type>::kernel_1a_c graph_type;
+
+ dlib::array<graph_type> samples;
+ std::vector<std::vector<bool> > labels;
+
+ make_data_sparse<graph_type>(samples, labels);
+ make_data_sparse<graph_type>(samples, labels);
+ make_data_sparse<graph_type>(samples, labels);
+ make_data_sparse<graph_type>(samples, labels);
+
+
+ test1<node_vector_type,edge_vector_type,vector_type>(samples, labels);
+ }
+
+
+
+ print_spinner();
+ // test with dense vectors
+ {
+ typedef matrix<double,3,1> node_vector_type;
+ typedef matrix<double,2,1> edge_vector_type;
+ typedef matrix<double,0,1> vector_type;
+ typedef dlib::graph<node_vector_type, edge_vector_type>::kernel_1a_c graph_type;
+
+ dlib::array<graph_type> samples;
+ std::vector<std::vector<bool> > labels;
+
+ make_data2<graph_type>(samples, labels);
+ make_data2<graph_type>(samples, labels);
+ make_data2<graph_type>(samples, labels);
+ make_data2<graph_type>(samples, labels);
+
+
+ test1<node_vector_type,edge_vector_type,vector_type>(samples, labels);
+ }
+ print_spinner();
+ // test with sparse vectors
+ {
+ typedef std::vector<std::pair<unsigned long,double> > vector_type;
+ typedef std::map<unsigned long, double> edge_vector_type;
+ typedef std::map<unsigned long, double> node_vector_type;
+ typedef dlib::graph<node_vector_type, edge_vector_type>::kernel_1a_c graph_type;
+
+ dlib::array<graph_type> samples;
+ std::vector<std::vector<bool> > labels;
+
+ make_data2_sparse<graph_type>(samples, labels);
+ make_data2_sparse<graph_type>(samples, labels);
+ make_data2_sparse<graph_type>(samples, labels);
+ make_data2_sparse<graph_type>(samples, labels);
+
+
+ test1<node_vector_type,edge_vector_type,vector_type>(samples, labels);
+ }
+ print_spinner();
+ // test with sparse vectors and dense mix
+ {
+ typedef matrix<double,0,1> vector_type;
+ typedef std::map<unsigned long, double> edge_vector_type;
+ typedef std::map<unsigned long, double> node_vector_type;
+ typedef dlib::graph<node_vector_type, edge_vector_type>::kernel_1a_c graph_type;
+
+ dlib::array<graph_type> samples;
+ std::vector<std::vector<bool> > labels;
+
+ make_data2_sparse<graph_type>(samples, labels);
+ make_data2_sparse<graph_type>(samples, labels);
+ make_data2_sparse<graph_type>(samples, labels);
+ make_data2_sparse<graph_type>(samples, labels);
+
+
+ test1<node_vector_type,edge_vector_type,vector_type>(samples, labels);
+ }
+ }
+ } a;
+
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/gui/CMakeLists.txt b/ml/dlib/dlib/test/gui/CMakeLists.txt
new file mode 100644
index 000000000..2ab3c2b47
--- /dev/null
+++ b/ml/dlib/dlib/test/gui/CMakeLists.txt
@@ -0,0 +1,20 @@
+#
+# This is a CMake makefile. You can find the cmake utility and
+# information about it at http://www.cmake.org
+#
+
+# create a variable called target_name and set it to the string "test"
+set (target_name gui)
+
+project(${target_name})
+
+add_subdirectory(../.. dlib_build)
+
+# add all the cpp files we want to compile to this list. This tells
+# cmake that they are part of our target (which is the executable named test)
+add_executable(${target_name} main.cpp )
+
+
+# Tell cmake to link our target executable to dlib.
+target_link_libraries(${target_name} dlib::dlib )
+
diff --git a/ml/dlib/dlib/test/gui/main.cpp b/ml/dlib/dlib/test/gui/main.cpp
new file mode 100644
index 000000000..d61aba8c0
--- /dev/null
+++ b/ml/dlib/dlib/test/gui/main.cpp
@@ -0,0 +1,840 @@
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "dlib/image_io.h"
+#include "dlib/array2d.h"
+#include "dlib/gui_core.h"
+#include "dlib/assert.h"
+#include "dlib/misc_api.h"
+
+#include "dlib/image_transforms.h"
+
+#include "dlib/timer.h"
+
+#include "dlib/gui_widgets.h"
+#include "dlib/queue.h"
+
+using namespace dlib;
+using namespace std;
+
+
+typedef dlib::array2d<hsi_pixel> image;
+
+
+
+
+#include "dlib/base64.h"
+
+
+
+
+class color_box : public draggable
+{
+ unsigned char red, green,blue;
+
+public:
+ color_box (
+ drawable_window& w,
+ rectangle area,
+ unsigned char red_,
+ unsigned char green_,
+ unsigned char blue_
+ ) :
+ draggable(w, MOUSE_WHEEL),
+ red(red_),
+ green(green_),
+ blue(blue_),
+ t(*this,&color_box::action)
+ {
+ rect = area;
+
+ t.set_delay_time(4);
+ // t.start();
+
+ set_draggable_area(rectangle(10,10,500,500));
+
+ enable_events();
+ }
+
+ ~color_box()
+ {
+ disable_events();
+ }
+
+private:
+
+ void action (
+ )
+ {
+ ++red;
+ parent.invalidate_rectangle(rect);
+ }
+
+ void draw (
+ const canvas& c
+ ) const
+ {
+ if (hidden == false )
+ {
+ fill_rect(c,rect,rgb_pixel(red,green,blue));
+ std::vector<point> poly;
+ poly.push_back((rect.tl_corner()+rect.tr_corner())/2);
+ poly.push_back((rect.tr_corner()+rect.br_corner())/2);
+ poly.push_back((rect.br_corner()+rect.bl_corner())/2);
+ poly.push_back((rect.bl_corner()+rect.tl_corner())/2);
+ draw_solid_convex_polygon(c,poly,rgb_alpha_pixel(0,0,0,70));
+ }
+ }
+
+ void on_wheel_up(
+ unsigned long state
+ )
+ {
+ if (state == base_window::NONE)
+ cout << "up scroll, NONE" << endl;
+ else if (state&base_window::LEFT)
+ cout << "up scroll, LEFT" << endl;
+ else if (state&base_window::RIGHT)
+ cout << "up scroll, RIGHT" << endl;
+ else if (state&base_window::MIDDLE)
+ cout << "up scroll, MIDDLE" << endl;
+ else if (state&base_window::SHIFT)
+ cout << "up scroll, SHIFT" << endl;
+ else if (state&base_window::CONTROL)
+ cout << "up scroll, CONTROL" << endl;
+
+ }
+
+ void on_wheel_down(
+ unsigned long state
+ )
+ {
+
+ if (state == base_window::NONE)
+ cout << "down scroll, NONE" << endl;
+ else if (state&base_window::LEFT)
+ cout << "down scroll, LEFT" << endl;
+ else if (state&base_window::RIGHT)
+ cout << "down scroll, RIGHT" << endl;
+ else if (state&base_window::MIDDLE)
+ cout << "down scroll, MIDDLE" << endl;
+ else if (state&base_window::SHIFT)
+ cout << "down scroll, SHIFT" << endl;
+ else if (state&base_window::CONTROL)
+ cout << "down scroll, CONTROL" << endl;
+
+ }
+
+
+ void on_window_resized ()
+ {
+ draggable::on_window_resized();
+ }
+ timer<color_box> t;
+};
+
+
+
+
+
+
+class win : public drawable_window
+{
+
+ label lbl_last_keydown;
+ label lbl_mod_shift;
+ label lbl_mod_control;
+ label lbl_mod_alt;
+ label lbl_mod_meta;
+ label lbl_mod_caps_lock;
+ label lbl_mod_num_lock;
+ label lbl_mod_scroll_lock;
+ void on_keydown (
+ unsigned long key,
+ bool is_printable,
+ unsigned long state
+ )
+ {
+ if (is_printable)
+ lbl_last_keydown.set_text(string("last keydown: ") + (char)key);
+ else
+ lbl_last_keydown.set_text(string("last keydown: nonprintable"));
+
+ if (state&base_window::KBD_MOD_SHIFT)
+ lbl_mod_shift.set_text("shift is on");
+ else
+ lbl_mod_shift.set_text("shift is off");
+
+ if (state&base_window::KBD_MOD_CONTROL)
+ lbl_mod_control.set_text("control is on");
+ else
+ lbl_mod_control.set_text("control is off");
+
+ if (state&base_window::KBD_MOD_ALT)
+ lbl_mod_alt.set_text("alt is on");
+ else
+ lbl_mod_alt.set_text("alt is off");
+
+
+ if (state&base_window::KBD_MOD_META)
+ lbl_mod_meta.set_text("meta is on");
+ else
+ lbl_mod_meta.set_text("meta is off");
+
+ if (state&base_window::KBD_MOD_CAPS_LOCK)
+ lbl_mod_caps_lock.set_text("caps_lock is on");
+ else
+ lbl_mod_caps_lock.set_text("caps_lock is off");
+
+ if (state&base_window::KBD_MOD_NUM_LOCK)
+ lbl_mod_num_lock.set_text("num_lock is on");
+ else
+ lbl_mod_num_lock.set_text("num_lock is off");
+
+
+ if (state&base_window::KBD_MOD_SCROLL_LOCK)
+ lbl_mod_scroll_lock.set_text("scroll_lock is on");
+ else
+ lbl_mod_scroll_lock.set_text("scroll_lock is off");
+
+ drawable_window::on_keydown(key,is_printable,state);
+ }
+
+ void rb_click (
+ )
+ {
+ if (rb.is_checked())
+ rb.set_name("radio button checked");
+ else
+ rb.set_name("radio button");
+ rb.set_checked();
+ }
+
+ void cb_sb_enabled (
+ toggle_button&
+ )
+ {
+ if (sb_enabled.is_checked())
+ {
+ sb.enable();
+ lb.enable();
+ b.enable();
+ }
+ else
+ {
+ lb.disable();
+ sb.disable();
+ b.disable();
+ }
+
+ if (sb_enabled.is_checked())
+ rb.enable();
+ else
+ rb.disable();
+
+ if (sb_enabled.is_checked())
+ tabs.enable();
+ else
+ tabs.disable();
+
+ if (sb_enabled.is_checked())
+ tf.enable();
+ else
+ tf.disable();
+
+ if (sb_enabled.is_checked())
+ tb.enable();
+ else
+ tb.disable();
+
+ }
+
+ void cb_sb_shown (
+ )
+ {
+ if (sb_shown.is_checked())
+ {
+ sb.show();
+ tabs.show();
+ lb.show();
+ }
+ else
+ {
+ sb.hide();
+ tabs.hide();
+ lb.hide();
+ }
+ }
+
+
+ void tab_change (
+ unsigned long new_idx,
+ unsigned long
+ )
+ {
+ tab_label.set_text(tabs.tab_name(new_idx));
+ }
+
+ void scroll_handler (
+ )
+ {
+ ostringstream sout;
+ sout << "scroll bar pos: " << sb.slider_pos();
+ sbl.set_text(sout.str());
+ }
+
+ void scroll2_handler (
+ )
+ {
+ sb.set_length(sb2.slider_pos());
+ ostringstream sout;
+ sout << "scroll bar2 pos: " << sb2.slider_pos();
+ sbl2.set_text(sout.str());
+ scroll_handler();
+ }
+
+ void scroll3_handler (
+ )
+ {
+ sb.set_max_slider_pos(sb3.slider_pos());
+ ostringstream sout;
+ sout << "scroll bar3 pos: " << sb3.slider_pos();
+ sbl3.set_text(sout.str());
+ scroll_handler();
+ }
+
+ void lb_double_click (
+ unsigned long
+ )
+ {
+ dlib::queue<unsigned long>::kernel_2a_c sel;
+ lb.get_selected(sel);
+ sel.reset();
+ while (sel.move_next())
+ {
+ cout << lb[sel.element()] << endl;
+ }
+ //message_box("list_box",lb[idx]);
+ }
+
+ void msg_box (
+ )
+ {
+ message_box("title","you clicked the ok button!\n HURRAY!");
+ }
+
+ static void try_this_junk (
+ void* param
+ )
+ {
+ win& p = *reinterpret_cast<win*>(param);
+ put_on_clipboard(p.tf.text() + "\nfoobar");
+
+
+ }
+
+ void on_set_clipboard (
+ )
+ {
+ create_new_thread(try_this_junk,this);
+ //try_this_junk(this);
+ }
+
+ static void try_this_junk2 (
+ void*
+ )
+ {
+
+ string temp;
+ get_from_clipboard(temp);
+ message_box("clipboard",temp);
+
+ }
+ void on_get_clipboard (
+ )
+ {
+ create_new_thread(try_this_junk2,this);
+ }
+
+
+ void on_show_msg_click (
+ )
+ {
+ message_box("title","This is a test message.",*this,&win::msg_box);
+ }
+
+ void on_menu_help (
+ )
+ {
+ message_box("About","This is the messy dlib gui regression test program");
+ }
+
+public:
+
+ ~win()
+ {
+ close_window();
+ }
+
+ void cbox_clicked (
+ )
+ {
+ if (cbox.is_checked())
+ cbl.set_text(cbox.name() + " box is checked");
+ else
+ cbl.set_text("box NOT is checked");
+ }
+
+ win (
+ ):
+ drawable_window(true),
+ lbl_last_keydown(*this),
+ lbl_mod_shift(*this),
+ lbl_mod_control(*this),
+ lbl_mod_alt(*this),
+ lbl_mod_meta(*this),
+ lbl_mod_caps_lock(*this),
+ lbl_mod_num_lock(*this),
+ lbl_mod_scroll_lock(*this),
+ b(*this),
+ btn_count(*this),
+ btn_get_clipboard(*this),
+ btn_set_clipboard(*this),
+ btn_show_message(*this),
+ cb1(*this,rectangle(100,100,200,200),255,0,0),
+ cb2(*this,rectangle(150,150,250,240),0,255,0),
+ cbl(*this),
+ cbox(*this),
+ group1(*this),
+ group2(*this),
+ group3(*this),
+ keyboard_count(1),
+ keydown(*this),
+ keyup(*this),
+ l1(*this),
+ l2(*this),
+ l3(*this),
+ lb(*this),
+ leave_count(*this),
+ left_down(*this),
+ left_up(*this),
+ middle_down(*this),
+ middle_up(*this),
+ mouse_state(*this),
+ mt(*this),
+ nrect(*this),
+ pos(*this),
+ rb(*this),
+ right_down(*this),
+ right_up(*this),
+ sb2(*this,scroll_bar::VERTICAL),
+ sb3(*this,scroll_bar::VERTICAL),
+ sb_enabled(*this),
+ sbl2(*this),
+ sbl3(*this),
+ sbl(*this),
+ sb_shown(*this),
+ sb(*this,scroll_bar::HORIZONTAL),
+ scroll(*this),
+ tab_label(*this),
+ tabs(*this),
+ tf(*this),
+ tb(*this),
+ mbar(*this)
+ {
+ bool use_bdf_fonts = false;
+
+ std::shared_ptr<bdf_font> f(new bdf_font);
+
+ if (use_bdf_fonts)
+ {
+
+ ifstream fin("/home/davis/source/10x20.bdf");
+ f->read_bdf_file(fin,0xFFFF);
+
+ mt.set_main_font(f);
+ }
+ //mt.hide();
+ mt.set_pos(5,200);
+
+
+ lbl_last_keydown.set_text("?");
+ lbl_mod_shift.set_text("?");
+ lbl_mod_control.set_text("?");
+ lbl_mod_alt.set_text("?");
+ lbl_mod_meta.set_text("?");
+ lbl_mod_caps_lock.set_text("?");
+ lbl_mod_num_lock.set_text("?");
+ lbl_mod_scroll_lock.set_text("?");
+
+ lbl_last_keydown.set_pos(20,420);
+ lbl_mod_shift.set_pos(20,lbl_last_keydown.bottom()+5);
+ lbl_mod_control.set_pos(20,lbl_mod_shift.bottom()+5);
+ lbl_mod_alt.set_pos(20,lbl_mod_control.bottom()+5);
+ lbl_mod_meta.set_pos(20,lbl_mod_alt.bottom()+5);
+ lbl_mod_caps_lock.set_pos(20,lbl_mod_meta.bottom()+5);
+ lbl_mod_num_lock.set_pos(20,lbl_mod_caps_lock.bottom()+5);
+ lbl_mod_scroll_lock.set_pos(20,lbl_mod_num_lock.bottom()+5);
+
+ lb.set_pos(580,200);
+ lb.set_size(200,300);
+ if (use_bdf_fonts)
+ lb.set_main_font(f);
+
+ dlib::queue<string>::kernel_2a_c qos;
+ string a;
+ a = "Davis"; qos.enqueue(a);
+ a = "king"; qos.enqueue(a);
+ a = "one"; qos.enqueue(a);
+ a = "two"; qos.enqueue(a);
+ a = "three"; qos.enqueue(a);
+ a = "yo yo yo alsdkjf asfj lsa jfsf\n this is a long phrase"; qos.enqueue(a);
+ a = "four"; qos.enqueue(a);
+ a = "five"; qos.enqueue(a);
+ a = "six"; qos.enqueue(a);
+ a = "seven"; qos.enqueue(a);
+ a = "eight"; qos.enqueue(a);
+ a = "nine"; qos.enqueue(a);
+ a = "ten"; qos.enqueue(a);
+ a = "eleven"; qos.enqueue(a);
+ a = "twelve"; qos.enqueue(a);
+ for (int i = 0; i < 1000; ++i)
+ {
+ a = "thirteen"; qos.enqueue(a);
+ }
+ lb.load(qos);
+ lb.select(1);
+ lb.select(2);
+ lb.select(3);
+ lb.select(5);
+ lb.enable_multiple_select();
+ lb.set_double_click_handler(*this,&win::lb_double_click);
+ // lb.disable_multiple_select();
+
+ btn_show_message.set_pos(50,350);
+ btn_show_message.set_name("message_box()");
+ mbar.set_number_of_menus(2);
+ mbar.set_menu_name(0,"File",'F');
+ mbar.set_menu_name(1,"Help",'H');
+ mbar.menu(0).add_menu_item(menu_item_text("show msg click",*this,&win::on_show_msg_click,'s'));
+ mbar.menu(0).add_menu_item(menu_item_text("get clipboard",*this,&win::on_get_clipboard,'g'));
+ mbar.menu(0).add_menu_item(menu_item_text("set clipboard",*this,&win::on_set_clipboard,'c'));
+ mbar.menu(0).add_menu_item(menu_item_separator());
+ mbar.menu(0).add_submenu(menu_item_submenu("submenu",'m'), submenu);
+ submenu.add_menu_item(menu_item_separator());
+ submenu.add_menu_item(menu_item_separator());
+ submenu.add_menu_item(menu_item_text("show msg click",*this,&win::on_show_msg_click,'s'));
+ submenu.add_menu_item(menu_item_text("get clipboard",*this,&win::on_get_clipboard,'g'));
+ submenu.add_menu_item(menu_item_text("set clipboard",*this,&win::on_set_clipboard,'c'));
+ submenu.add_menu_item(menu_item_separator());
+ submenu.add_menu_item(menu_item_separator());
+ mbar.menu(1).add_menu_item(menu_item_text("About",*this,&win::on_menu_help,'A'));
+
+ btn_show_message.set_click_handler(*this,&win::on_show_msg_click);
+ btn_get_clipboard.set_pos(btn_show_message.right()+5,btn_show_message.top());
+ btn_get_clipboard.set_name("get_from_clipboard()");
+ btn_get_clipboard.set_click_handler(*this,&win::on_get_clipboard);
+
+ btn_get_clipboard.set_style(button_style_toolbar1());
+ btn_set_clipboard.set_pos(btn_get_clipboard.right()+5,btn_get_clipboard.top());
+ btn_set_clipboard.set_name("put_on_clipboard()");
+ btn_set_clipboard.set_click_handler(*this,&win::on_set_clipboard);
+
+ nrect.set_size(700,500);
+ nrect.set_name("test widgets");
+ nrect.set_pos(2,mbar.bottom()+2);
+
+ //throw dlib::error("holy crap batman");
+ tab_label.set_pos(10,440);
+
+ tabs.set_click_handler(*this,&win::tab_change);
+ tabs.set_pos(5,mbar.bottom()+10);
+ tabs.set_size(280,100);
+ tabs.set_number_of_tabs(3);
+ tabs.set_tab_name(0,"davis");
+ tabs.set_tab_name(1,"edward");
+ tabs.set_tab_name(2,"king alsklsdkfj asfd");
+ tabs.set_tab_group(0,group1);
+ tabs.set_tab_group(1,group2);
+ tabs.set_tab_group(2,group3);
+
+ l1.set_text("group one");
+ l2.set_text("group two");
+ l3.set_text("group three");
+
+ group1.add(l1,0,0);
+ group2.add(l2,20,10);
+ group3.add(l3,0,0);
+
+
+
+ sb_enabled.set_name("enabled");
+ sb_shown.set_name("shown");
+ sb_shown.set_checked();
+ sb_enabled.set_checked();
+ sb_shown.set_click_handler(*this,&win::cb_sb_shown);
+ sb_enabled.set_click_handler(*this,&win::cb_sb_enabled);
+
+ sb_shown.set_tooltip_text("I'm a checkbox");
+
+ rb.set_click_handler(*this,&win::rb_click);
+
+
+ sb3.set_pos(440,mbar.bottom()+10);
+ sb3.set_max_slider_pos(300);
+ sb3.set_slider_pos(150);
+ sb3.set_length(300);
+ sb2.set_pos(470,mbar.bottom()+10);
+ sb2.set_max_slider_pos(300);
+ sb2.set_length(300);
+ sb.set_pos(500,mbar.bottom()+10);
+ sb.set_max_slider_pos(30);
+ sb.set_length(300);
+
+
+ sb.set_scroll_handler(*this,&win::scroll_handler);
+ sb2.set_scroll_handler(*this,&win::scroll2_handler);
+ sb3.set_scroll_handler(*this,&win::scroll3_handler);
+ sbl.set_pos(540,mbar.bottom()+20);
+ sbl2.set_pos(540,mbar.bottom()+40);
+ sbl3.set_pos(540,mbar.bottom()+60);
+
+ cbox.set_pos(300,mbar.bottom()+30);
+ cbox.set_name("davis king");
+ cbox.set_click_handler(*this,&win::cbox_clicked);
+
+ cbl.set_pos(300,cbox.get_rect().bottom()+1);
+ cbox.set_checked();
+ sb_enabled.set_pos(cbox.get_rect().left(),cbox.get_rect().bottom()+20);
+ sb_shown.set_pos(sb_enabled.get_rect().left(),sb_enabled.get_rect().bottom()+2);
+
+
+
+ if (use_bdf_fonts)
+ rb.set_main_font(f);
+ rb.set_name("radio button");
+ rb.set_pos(sb_shown.get_rect().left(),sb_shown.get_rect().bottom()+2);
+
+
+ cb1.set_z_order(10);
+ cb2.set_z_order(20);
+
+ pos.set_pos(50,50);
+ left_up.set_pos(50,70);
+ left_down.set_pos(50,90);
+ middle_up.set_pos(50,110);
+ middle_down.set_pos(50,130);
+ right_up.set_pos(50,150);
+ right_down.set_pos(50,170);
+
+ mouse_state.set_pos(50,190);
+
+ leave_count.set_pos(50,210);
+
+ scroll_count = 0;
+ scroll.set_pos(50,230);
+
+ btn_count.set_pos(50,250);
+
+
+ keydown.set_pos(50,270);
+ keyup.set_pos(50,290);
+
+ tf.set_pos(50,310);
+ tf.set_text("Davis685g@");
+ tf.set_width(500);
+ tf.set_text_color(rgb_pixel(255,0,0));
+ tf.set_enter_key_handler(*this,&win::on_enter_key);
+ tf.set_focus_lost_handler(*this,&win::on_tf_focus_lost);
+
+ tb.set_pos(250,400);
+ tb.set_text("initial test\nstring");
+ tb.set_size(300,300);
+ tb.set_text_color(rgb_pixel(255,0,0));
+ tb.set_enter_key_handler(*this,&win::on_enter_key);
+ tb.set_focus_lost_handler(*this,&win::on_tf_focus_lost);
+
+
+ button_count = 0;
+ count = 0;
+ b.set_name("button");
+ b.set_pos(540,100);
+ b.set_click_handler(*this,&win::on_click);
+ b.set_tooltip_text("hurray i'm a button!");
+ if (use_bdf_fonts)
+ b.set_main_font(f);
+
+
+ set_size(815,730);
+
+ nrect.wrap_around(
+ cbox.get_rect() +
+ rb.get_rect() +
+ sb_enabled.get_rect() +
+ sb_shown.get_rect());
+
+ flip = 0;
+ open_file_box(*this,&win::on_open_file);
+ open_existing_file_box(*this,&win::on_open_file);
+ save_file_box(*this,&win::on_open_file);
+
+ if (use_bdf_fonts)
+ {
+ tf.set_main_font(f);
+ tb.set_main_font(f);
+ }
+ if (use_bdf_fonts)
+ tabs.set_main_font(f);
+
+ }
+
+private:
+
+
+ void on_enter_key()
+ {
+ cout << "enter key pressed" << endl;
+ }
+
+ void on_tf_focus_lost()
+ {
+ cout << "text field/box lost focus" << endl;
+ }
+
+
+ void on_open_file (const std::string& file)
+ {
+ message_box("file opened",file);
+ }
+
+
+
+
+ void on_click (
+ )
+ {
+ ostringstream sout;
+ sout << "text field: " << tf.text();
+ ++button_count;
+ btn_count.set_text(sout.str());
+
+ if (flip == 0)
+ {
+ flip = 1;
+ lb.set_size(200,200);
+ }
+ else if (flip == 1)
+ {
+ flip = 2;
+ lb.set_size(150,200);
+ }
+ else if (flip == 2)
+ {
+ flip = 3;
+ lb.set_size(150,300);
+ }
+ else
+ {
+ flip = 0;
+ lb.set_size(200,300);
+ }
+ }
+
+
+ button b;
+ label btn_count;
+ button btn_get_clipboard;
+ button btn_set_clipboard;
+ button btn_show_message;
+ int button_count;
+ color_box cb1;
+ color_box cb2;
+ label cbl;
+ check_box cbox;
+ int count;
+ int flip;
+ widget_group group1;
+ widget_group group2;
+ widget_group group3;
+ int keyboard_count;
+ label keydown;
+ label keyup;
+ label l1;
+ label l2;
+ label l3;
+ list_box lb;
+ label leave_count;
+ label left_down;
+ label left_up;
+ label middle_down;
+ label middle_up;
+ label mouse_state;
+ mouse_tracker mt;
+ named_rectangle nrect;
+ label pos;
+ radio_button rb;
+ label right_down;
+ label right_up;
+ scroll_bar sb2;
+ scroll_bar sb3;
+ check_box sb_enabled;
+ label sbl2;
+ label sbl3;
+ label sbl;
+ check_box sb_shown;
+ scroll_bar sb;
+ int scroll_count;
+ label scroll;
+ label tab_label;
+ tabbed_display tabs;
+ text_field tf;
+ text_box tb;
+ menu_bar mbar;
+ popup_menu submenu;
+
+};
+
+
+win w;
+
+int main()
+{
+
+ try
+ {
+
+ image_window win;
+
+ array2d<unsigned char> img;
+ img.set_size(100,100);
+ assign_all_pixels(img,0);
+
+ fill_rect(img, rectangle(1,1,1,1), 255);
+ fill_rect(img, rectangle(1,3,2,5), 255);
+ fill_rect(img, rectangle(4,3,5,4), 255);
+ fill_rect(img, rectangle(9,9,13,10), 255);
+
+ win.set_image(img);
+
+ win.add_overlay(image_display::overlay_rect(rectangle(1,1,1,1), rgb_pixel(255,0,0)));
+ win.add_overlay(image_display::overlay_rect(rectangle(1,3,2,5), rgb_pixel(255,0,0)));
+ win.add_overlay(image_display::overlay_rect(rectangle(4,3,5,4), rgb_pixel(255,0,0)));
+ win.add_overlay(image_display::overlay_rect(rectangle(9,9,13,10), rgb_pixel(255,0,0)));
+
+
+
+ w.set_pos (100,200);
+ w.set_title("test window");
+ w.show();
+
+ w.wait_until_closed();
+ }
+ catch (exception& e)
+ {
+ cout << e.what() << endl;
+ }
+
+}
diff --git a/ml/dlib/dlib/test/hash.cpp b/ml/dlib/dlib/test/hash.cpp
new file mode 100644
index 000000000..94930e629
--- /dev/null
+++ b/ml/dlib/dlib/test/hash.cpp
@@ -0,0 +1,369 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/hash.h>
+#include <dlib/rand.h>
+#include <dlib/matrix.h>
+#include <dlib/byte_orderer.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.hash");
+
+
+ template <typename T>
+ void to_little (
+ std::vector<T>& item
+ )
+ {
+ byte_orderer bo;
+ for (unsigned long i = 0; i < item.size(); ++i)
+ bo.host_to_little(item[i]);
+ }
+
+
+ template <typename T>
+ void to_little (
+ matrix<T>& item
+ )
+ {
+ byte_orderer bo;
+ for (long r = 0; r < item.nr(); ++r)
+ {
+ for (long c = 0; c < item.nc(); ++c)
+ {
+ bo.host_to_little(item(r,c));
+ }
+ }
+ }
+
+ // Run the official test for MurmurHash3
+ void murmur_hash_test()
+ {
+ uint8 key[256];
+ uint32 hashes[256];
+ uint32 final = 0;
+
+ memset(key,0,sizeof(key));
+ memset(hashes,0,sizeof(hashes));
+
+ // Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as
+ // the seed.
+ for(int i = 0; i < 256; i++)
+ {
+ key[i] = (uint8)i;
+
+ hashes[i] = murmur_hash3(key,i,256-i);
+ }
+
+ byte_orderer bo;
+ bo.host_to_little(hashes);
+ final = murmur_hash3(hashes,sizeof(hashes),0);
+
+ // using ostringstream to avoid compiler error in visual studio 2005
+ ostringstream sout;
+ sout << hex << final;
+ dlog << LINFO << "final: "<< sout.str();
+ DLIB_TEST(final == 0xB0F57EE3);
+ }
+
+ void murmur_hash_128_test()
+ {
+ uint8 key[256];
+ uint64 hashes[256*2];
+ uint32 final = 0;
+
+ memset(key,0,sizeof(key));
+ memset(hashes,0,sizeof(hashes));
+
+ // Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as
+ // the seed.
+ for(int i = 0; i < 256; i++)
+ {
+ key[i] = (uint8)i;
+
+ const std::pair<uint64,uint64> temp = murmur_hash3_128bit(key,i,256-i);
+ hashes[2*i] = temp.first;
+ hashes[2*i+1] = temp.second;
+ }
+
+ byte_orderer bo;
+ bo.host_to_little(hashes);
+ final = static_cast<uint32>(murmur_hash3_128bit(hashes,sizeof(hashes),0).first);
+
+ // using ostringstream to avoid compiler error in visual studio 2005
+ ostringstream sout;
+ sout << hex << final;
+ dlog << LINFO << "final 64: "<< sout.str();
+ DLIB_TEST(final == 0x6384BA69);
+ }
+
+ void test_murmur_hash_128_4()
+ {
+ byte_orderer bo;
+ dlib::rand rnd;
+ for (int i = 0; i < 100; ++i)
+ {
+ uint32 buf[4] = { rnd.get_random_32bit_number(),
+ rnd.get_random_32bit_number(),
+ rnd.get_random_32bit_number(),
+ rnd.get_random_32bit_number()
+ };
+
+ bo.host_to_little(buf);
+
+ std::pair<uint64,uint64> temp1, temp2;
+
+ // Make sure the 4 integer version of murmur hash does the same thing
+ // as the memory block version.
+ temp1 = murmur_hash3_128bit(buf, sizeof(buf), 0);
+ temp2 = murmur_hash3_128bit(buf[0], buf[1], buf[2], buf[3]);
+ DLIB_TEST( temp1.first == temp2.first);
+ DLIB_TEST( temp1.second == temp2.second);
+ }
+ }
+
+ void test_murmur_hash_128_3()
+ {
+ byte_orderer bo;
+ dlib::rand rnd;
+ for (int i = 0; i < 100; ++i)
+ {
+ uint64 buf[2] = { rnd.get_random_64bit_number(),
+ rnd.get_random_64bit_number(),
+ };
+
+ const uint32 seed = rnd.get_random_32bit_number();
+
+ bo.host_to_little(buf);
+ std::pair<uint64,uint64> temp1, temp2;
+
+ // Make sure the 3 integer version of murmur hash does the same thing
+ // as the memory block version.
+ temp1 = murmur_hash3_128bit(buf, sizeof(buf), seed);
+ temp2 = murmur_hash3_128bit_3(buf[0], buf[1], seed);
+ DLIB_TEST( temp1.first == temp2.first);
+ DLIB_TEST( temp1.second == temp2.second);
+ }
+ }
+
+ void test_murmur_hash_64_2()
+ {
+ byte_orderer bo;
+ dlib::rand rnd;
+ for (int i = 0; i < 100; ++i)
+ {
+ uint32 val = rnd.get_random_32bit_number();
+ const uint32 seed = rnd.get_random_32bit_number();
+
+
+ bo.host_to_little(val);
+ uint32 temp1, temp2;
+
+ // Make sure the 2 integer version of murmur hash does the same thing
+ // as the memory block version.
+ temp1 = murmur_hash3(&val, sizeof(val), seed);
+ temp2 = murmur_hash3_2(val, seed);
+ DLIB_TEST(temp1 == temp2);
+ }
+ }
+
+ void test_murmur_hash_64_3()
+ {
+ byte_orderer bo;
+ dlib::rand rnd;
+ for (int i = 0; i < 100; ++i)
+ {
+ uint32 buf[2] = {rnd.get_random_32bit_number(),
+ rnd.get_random_32bit_number()};
+ const uint32 seed = rnd.get_random_32bit_number();
+
+
+ bo.host_to_little(buf);
+ uint32 temp1, temp2;
+
+ // Make sure the 2 integer version of murmur hash does the same thing
+ // as the memory block version.
+ temp1 = murmur_hash3(&buf, sizeof(buf), seed);
+ temp2 = murmur_hash3_3(buf[0], buf[1], seed);
+ DLIB_TEST(temp1 == temp2);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ uint64 slow_count_bits ( uint64 v)
+ {
+ uint64 count = 0;
+ for (int i = 0; i < 64; ++i)
+ {
+ if (v&1)
+ ++count;
+ v >>= 1;
+ }
+ return count;
+ }
+
+
+ uint32 slow_count_bits ( uint32 v)
+ {
+ uint32 count = 0;
+ for (int i = 0; i < 32; ++i)
+ {
+ if (v&1)
+ ++count;
+ v >>= 1;
+ }
+ return count;
+ }
+
+
+// ----------------------------------------------------------------------------------------
+
+ void test_hamming_stuff()
+ {
+ dlib::rand rnd;
+ for (int i = 0; i < 10000; ++i)
+ {
+ uint32 v = rnd.get_random_32bit_number();
+ uint64 v2 = rnd.get_random_64bit_number();
+ DLIB_TEST(slow_count_bits(v) == count_bits(v));
+ DLIB_TEST(slow_count_bits(v2) == count_bits(v2));
+ }
+
+ DLIB_TEST(hamming_distance((uint32)0x1F, (uint32)0x0F) == 1);
+ DLIB_TEST(hamming_distance((uint32)0x1F, (uint32)0x1F) == 0);
+ DLIB_TEST(hamming_distance((uint32)0x1F, (uint32)0x19) == 2);
+ DLIB_TEST(hamming_distance((uint32)0x2F, (uint32)0x19) == 4);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_hash : public tester
+ {
+ public:
+ test_hash (
+ ) :
+ tester ("test_hash",
+ "Runs tests on the hash routines.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+
+ test_hamming_stuff();
+
+ murmur_hash_test();
+ murmur_hash_128_test();
+
+ std::string str1 = "some random string";
+ matrix<unsigned char> mat(2,2);
+
+ mat = 1,2,3,4;
+
+ matrix<uint64> mat2(2,3);
+
+ mat2 = 1,2,3,4,5,6;
+
+ to_little(mat2);
+
+ std::vector<unsigned char> v(4);
+ v[0] = 'c';
+ v[1] = 'a';
+ v[2] = 't';
+ v[3] = '!';
+
+ std::vector<uint16> v2(4);
+ v[0] = 'c';
+ v[1] = 'a';
+ v[2] = 't';
+ v[3] = '!';
+ to_little(v2);
+
+ std::map<unsigned char, unsigned char> m;
+ m['c'] = 'C';
+ m['a'] = 'A';
+ m['t'] = 'T';
+
+ dlog << LINFO << "hash(str1): "<< dlib::hash(str1);
+ dlog << LINFO << "hash(v): "<< dlib::hash(v);
+ dlog << LINFO << "hash(v2): "<< dlib::hash(v2);
+ dlog << LINFO << "hash(m): "<< dlib::hash(m);
+ dlog << LINFO << "hash(mat): "<< dlib::hash(mat);
+ dlog << LINFO << "hash(mat2): "<< dlib::hash(mat2);
+
+ uint32 ui1 = 123485393;
+ uint64 ui2 = ui1;
+ ui2 *= ui2;
+ ui2 *= ui2;
+ dlog << LINFO << "hash(ui1): "<< dlib::hash(ui1);
+ dlog << LINFO << "hash(ui2): "<< dlib::hash(ui2);
+ dlog << LINFO << "hash(make_pair(ui2,ui1)): "<< dlib::hash(make_pair(ui2,ui1));
+ dlog << LINFO << "hash(make_pair(ui2,ui2)): "<< dlib::hash(make_pair(ui2,ui2));
+ dlog << LINFO << "hash(make_pair(ui1,ui1)): "<< dlib::hash(make_pair(ui1,ui1));
+ dlog << LINFO << "hash(ui1,3): "<< dlib::hash(ui1,3);
+ dlog << LINFO << "hash(ui2,3): "<< dlib::hash(ui2,3);
+ dlog << LINFO << "hash(make_pair(ui2,ui1),3): "<< dlib::hash(make_pair(ui2,ui1),3);
+ dlog << LINFO << "hash(make_pair(ui2,ui2),3): "<< dlib::hash(make_pair(ui2,ui2),3);
+ dlog << LINFO << "hash(make_pair(ui1,ui1),3): "<< dlib::hash(make_pair(ui1,ui1),3);
+
+ DLIB_TEST(dlib::hash(ui1) == 0x63e272e4);
+ DLIB_TEST(dlib::hash(ui2) == 0xaf55561a);
+ DLIB_TEST(dlib::hash(make_pair(ui2,ui1)) == 0x52685376);
+ DLIB_TEST(dlib::hash(make_pair(ui2,ui2)) == 0xd25d6929);
+ DLIB_TEST(dlib::hash(make_pair(ui1,ui1)) == 0xeea3b63e);
+ DLIB_TEST(dlib::hash(ui1,3) == 0x95d1c4c0);
+ DLIB_TEST(dlib::hash(ui2,3) == 0x6ada728d);
+ DLIB_TEST(dlib::hash(make_pair(ui2,ui1),3) == 0x2f72a0ff);
+ DLIB_TEST(dlib::hash(make_pair(ui2,ui2),3) == 0xac1407f0);
+ DLIB_TEST(dlib::hash(make_pair(ui1,ui1),3) == 0x39ad637a);
+
+
+ DLIB_TEST(dlib::hash(str1) == 0x3ffe6bf6);
+ DLIB_TEST(dlib::hash(v) == 0xf1af2ca6);
+ DLIB_TEST(dlib::hash(v2) == 0x63852afc);
+ DLIB_TEST(dlib::hash(m) == 0xaacc3f6f);
+ DLIB_TEST(dlib::hash(mat) == 0x3e349da5);
+ DLIB_TEST(dlib::hash(mat2) == 0x3a95dc52);
+ DLIB_TEST(murmur_hash3(&str1[0], str1.size(), 0) == 0x3ffe6bf6);
+
+ dlog << LINFO << "hash(str1,1): "<< dlib::hash(str1,1);
+ dlog << LINFO << "hash(v,3): "<< dlib::hash(v,3);
+ dlog << LINFO << "hash(v2,3): "<< dlib::hash(v2,3);
+ dlog << LINFO << "hash(m,4): "<< dlib::hash(m,4);
+ dlog << LINFO << "hash(mat,5): "<< dlib::hash(mat,5);
+ dlog << LINFO << "hash(mat2,6): "<< dlib::hash(mat2,6);
+
+ DLIB_TEST(dlib::hash(str1,1) == 0xb17cea93);
+ DLIB_TEST(dlib::hash(v,3) == 0x7ec9284c);
+ DLIB_TEST(dlib::hash(v2,3) == 0xb2ce147f);
+ DLIB_TEST(dlib::hash(m,4) == 0xfa5e7ac2);
+ DLIB_TEST(dlib::hash(mat,5) == 0x8de27259);
+ DLIB_TEST(dlib::hash(mat2,6) == 0xb8aa7714);
+ DLIB_TEST(murmur_hash3(&str1[0], str1.size(), 1) == 0xb17cea93);
+
+ test_murmur_hash_128_4();
+ test_murmur_hash_128_3();
+ test_murmur_hash_64_2();
+ test_murmur_hash_64_3();
+ }
+ } a;
+
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/hash_map.cpp b/ml/dlib/dlib/test/hash_map.cpp
new file mode 100644
index 000000000..09af09936
--- /dev/null
+++ b/ml/dlib/dlib/test/hash_map.cpp
@@ -0,0 +1,450 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/hash_map.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.hash_map");
+
+ template <
+ typename hash_map
+ >
+ void hash_map_kernel_test (
+ )
+ /*!
+ requires
+ - hash_map is an implementation of hash_map/hash_map_kernel_abstract.h and
+ is instantiated to map int to int
+ ensures
+ - runs tests on hash_map for compliance with the specs
+ !*/
+ {
+
+ srand(static_cast<unsigned int>(time(0)));
+
+ print_spinner();
+
+
+ hash_map test, test2;
+
+ enumerable<map_pair<int,int> >& e = test;
+ DLIB_TEST(e.at_start() == true);
+
+ for (int j = 0; j < 4; ++j)
+ {
+ print_spinner();
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+
+
+ int a,b;
+ a = 8;
+ b = 94;
+ test.add(a,b);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(test.is_in_domain(8) == true);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+ DLIB_TEST(test[8] == 94);
+ a = 53;
+ b = 4;
+ test.add(a,b);
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test.is_in_domain(53) == true);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+ DLIB_TEST(test[53] == 4);
+
+
+ swap(test,test2);
+
+
+ DLIB_TEST_MSG(test2.size() == 2,test2.size());
+ DLIB_TEST(test2.is_in_domain(8) == true);
+ DLIB_TEST(test2.is_in_domain(5) == false);
+ DLIB_TEST(test2.is_in_domain(0) == false);
+ DLIB_TEST(test2.is_in_domain(-999) == false);
+ DLIB_TEST(test2.is_in_domain(4999) == false);
+ DLIB_TEST(test2[8] == 94);
+ DLIB_TEST(test2.size() == 2);
+ DLIB_TEST(test2.is_in_domain(53) == true);
+ DLIB_TEST(test2.is_in_domain(5) == false);
+ DLIB_TEST(test2.is_in_domain(0) == false);
+ DLIB_TEST(test2.is_in_domain(-999) == false);
+ DLIB_TEST(test2.is_in_domain(4999) == false);
+ DLIB_TEST(test2[53] == 4);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_in_domain(8) == false);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_in_domain(53) == false);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+
+
+ test.clear();
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+ test.clear();
+ DLIB_TEST(test.size() == 0);
+
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+
+ int count = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element().key() == test.element().key());
+ DLIB_TEST(test.element().value() == test.element().value());
+ DLIB_TEST(test.element().key() == test.element().key());
+ DLIB_TEST(test.element().value() == test.element().value());
+
+
+
+ ++count;
+ }
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+
+ DLIB_TEST(count == 10000);
+
+ test.swap(test2);
+
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test2.size() == 10000);
+ count = 0;
+ test2.reset();
+
+ test2.move_next();
+ test2.element().value() = 99;
+ DLIB_TEST(test2[test2.element().key()] == 99);
+ DLIB_TEST(test2.element().value() == 99);
+
+ test2.reset();
+
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2[test2.element().key()] == test2.element().value());
+ DLIB_TEST(test2.element().key() == test2.element().key());
+ DLIB_TEST(test2.element().value() == test2.element().value());
+ DLIB_TEST(test2.element().key() == test2.element().key());
+ DLIB_TEST(test2.element().value() == test2.element().value());
+
+ ++count;
+ }
+ DLIB_TEST(test2.size() == 10000);
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.move_next() == false);
+
+
+
+ test2.clear();
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.at_start() == true);
+
+ while (test.size() < 20000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ DLIB_TEST(test.at_start() == true);
+
+ {
+ int* array1 = new int[test.size()];
+ int* array2 = new int[test.size()];
+
+ int* tmp1 = array1;
+ int* tmp2 = array2;
+
+
+
+ // serialize the state of test, then clear test, then
+ // load the state back into test.
+ ostringstream sout;
+ serialize(test,sout);
+ DLIB_TEST(test.at_start() == true);
+ istringstream sin(sout.str());
+ test.clear();
+ deserialize(test,sin);
+ DLIB_TEST(test.at_start() == true);
+
+
+ count = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element().key() == test.element().key());
+ DLIB_TEST(test.element().value() == test.element().value());
+ DLIB_TEST(test.element().key() == test.element().key());
+ DLIB_TEST(test.current_element_valid() == true);
+ *tmp1 = test.element().key();
+ *tmp2 = test.element().value();
+ ++tmp1;
+ ++tmp2;
+ ++count;
+ }
+ DLIB_TEST(count == 20000);
+
+ tmp1 = array1;
+ tmp2 = array2;
+ for (int i = 0; i < 20000; ++i)
+ {
+ DLIB_TEST(test.is_in_domain(*tmp1) == true);
+ DLIB_TEST(test[*tmp1] == *tmp2);
+ ++tmp1;
+ ++tmp2;
+ }
+
+ DLIB_TEST(test.size() == 20000);
+
+ tmp1 = array1;
+ tmp2 = array2;
+ count = 0;
+ while (test.size() > 10000)
+ {
+ test.remove(*tmp1,a,b);
+ DLIB_TEST(*tmp1 == a);
+ DLIB_TEST(*tmp2 == b);
+ ++tmp1;
+ ++tmp2;
+ ++count;
+ }
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test.size() == 10000);
+
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element().key() == *tmp1);
+ DLIB_TEST(test.element().key() == *tmp1);
+ DLIB_TEST(test.element().key() == *tmp1);
+ DLIB_TEST(test.element().value() == *tmp2);
+ DLIB_TEST(test.element().value() == *tmp2);
+ DLIB_TEST(test.element().value() == *tmp2);
+ ++tmp1;
+ ++tmp2;
+ ++count;
+ }
+ DLIB_TEST(count == 20000);
+ DLIB_TEST(test.size() == 10000);
+
+ while (test.size() < 20000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ test2.swap(test);
+
+ count = 0;
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2.element().key() == test2.element().key());
+ DLIB_TEST(test2.element().value() == test2.element().value());
+ DLIB_TEST(test2.element().key() == test2.element().key());
+
+ ++count;
+ }
+
+ DLIB_TEST(count == 20000);
+ DLIB_TEST(test2.size() == 20000);
+
+ int c = 0;
+ while (test2.size()>0)
+ {
+ test2.remove_any(b,c);
+
+ }
+
+ DLIB_TEST(test2.size() == 0);
+ delete [] array1;
+ delete [] array2;
+ }
+
+ test.clear();
+ test2.clear();
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ count = 0;
+ while (test.move_next())
+ {
+
+ DLIB_TEST(test[test.element().key()] == test.element().value());
+
+ ++count;
+ if (count == 5000)
+ break;
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ test.reset();
+
+ count = 0;
+
+ while (test.move_next())
+ {
+
+ ++count;
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ DLIB_TEST(count == 10000);
+
+
+ test.clear();
+ test2.clear();
+ }
+
+
+
+
+ {
+ test.clear();
+ DLIB_TEST(test.size() == 0);
+ int a = 5;
+ int b = 6;
+ test.add(a,b);
+ a = 7;
+ b = 8;
+ test.add(a,b);
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test[7] == 8);
+ DLIB_TEST(test[5] == 6);
+ DLIB_TEST(test.is_in_domain(7));
+ DLIB_TEST(test.is_in_domain(5));
+ test.destroy(7);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(!test.is_in_domain(7));
+ DLIB_TEST(test.is_in_domain(5));
+ test.destroy(5);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(!test.is_in_domain(7));
+ DLIB_TEST(!test.is_in_domain(5));
+ }
+
+
+
+ }
+
+
+
+
+
+ class hash_map_tester : public tester
+ {
+ public:
+ hash_map_tester (
+ ) :
+ tester ("test_hash_map",
+ "Runs tests on the hash_map component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ hash_map_kernel_test<hash_map<int,int,14>::kernel_1a>();
+
+ dlog << LINFO << "testing kernel_1b_c";
+ hash_map_kernel_test<hash_map<int,int,14>::kernel_1a_c>();
+
+ dlog << LINFO << "testing kernel_1b";
+ hash_map_kernel_test<hash_map<int,int,14>::kernel_1b>();
+
+ dlog << LINFO << "testing kernel_1a_c";
+ hash_map_kernel_test<hash_map<int,int,14>::kernel_1b_c>();
+
+ dlog << LINFO << "testing kernel_1c";
+ hash_map_kernel_test<hash_map<int,int,14>::kernel_1c>();
+
+ dlog << LINFO << "testing kernel_1c_c";
+ hash_map_kernel_test<hash_map<int,int,14>::kernel_1c_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/hash_set.cpp b/ml/dlib/dlib/test/hash_set.cpp
new file mode 100644
index 000000000..02b665bdb
--- /dev/null
+++ b/ml/dlib/dlib/test/hash_set.cpp
@@ -0,0 +1,387 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/hash_set.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.hash_set");
+
+ template <
+ typename hash_set
+ >
+ void hash_set_kernel_test (
+ )
+ /*!
+ requires
+ - hash_set is an implementation of hash_set/hash_set_kernel_abstract.h and
+ is instantiated with int
+ ensures
+ - runs tests on hash_set for compliance with the specs
+ !*/
+ {
+
+
+ srand(static_cast<unsigned int>(time(0)));
+
+
+ print_spinner();
+
+ hash_set test, test2;
+
+
+ enumerable<const int>& e = test;
+ DLIB_TEST(e.at_start() == true);
+
+
+ for (int j = 0; j < 4; ++j)
+ {
+ print_spinner();
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+
+
+ int a,b = 0;
+ a = 8;
+ test.add(a);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(test.is_member(8) == true);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+ a = 53;
+ test.add(a);
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test.is_member(53) == true);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+
+
+ swap(test,test2);
+
+
+
+ DLIB_TEST(test2.is_member(8) == true);
+ DLIB_TEST(test2.is_member(5) == false);
+ DLIB_TEST(test2.is_member(0) == false);
+ DLIB_TEST(test2.is_member(-999) == false);
+ DLIB_TEST(test2.is_member(4999) == false);
+ DLIB_TEST(test2.size() == 2);
+ DLIB_TEST(test2.is_member(53) == true);
+ DLIB_TEST(test2.is_member(5) == false);
+ DLIB_TEST(test2.is_member(0) == false);
+ DLIB_TEST(test2.is_member(-999) == false);
+ DLIB_TEST(test2.is_member(4999) == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_member(8) == false);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_member(53) == false);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+
+
+ test.clear();
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+ test.clear();
+ DLIB_TEST(test.size() == 0);
+
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+
+ int count = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element() == test.element());
+ DLIB_TEST(test.element() == test.element());
+ DLIB_TEST(test.element() == test.element());
+
+
+ ++count;
+ }
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+
+ DLIB_TEST(count == 10000);
+
+ test.swap(test2);
+
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test2.size() == 10000);
+ count = 0;
+ test2.reset();
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(test2.element() == test2.element());
+
+ ++count;
+ }
+ DLIB_TEST(test2.size() == 10000);
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.move_next() == false);
+
+
+
+ test2.clear();
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.at_start() == true);
+
+ while (test.size() < 20000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ DLIB_TEST(test.at_start() == true);
+
+ {
+ int* array = new int[test.size()];
+ int* tmp = array;
+
+ // serialize the state of test, then clear test, then
+ // load the state back into test.
+ ostringstream sout;
+ serialize(test,sout);
+ DLIB_TEST(test.at_start() == true);
+ istringstream sin(sout.str());
+ test.clear();
+ deserialize(test,sin);
+
+
+
+ count = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element() == test.element());
+ DLIB_TEST(test.element() == test.element());
+ DLIB_TEST(test.element() == test.element());
+ *tmp = test.element();
+ ++tmp;
+ ++count;
+ }
+ DLIB_TEST(count == 20000);
+
+ tmp = array;
+ for (int i = 0; i < 20000; ++i)
+ {
+ DLIB_TEST(test.is_member(*tmp) == true);
+ ++tmp;
+ }
+
+ DLIB_TEST(test.size() == 20000);
+
+ tmp = array;
+ count = 0;
+ while (test.size() > 10000)
+ {
+ test.remove(*tmp,a);
+ DLIB_TEST(*tmp == a);
+ ++tmp;
+ ++count;
+ }
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test.size() == 10000);
+
+ while (test.move_next())
+ {
+ ++count;
+ }
+ DLIB_TEST(count == 20000);
+ DLIB_TEST(test.size() == 10000);
+
+ while (test.size() < 20000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ test2.swap(test);
+
+ count = 0;
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(test2.element() == test2.element());
+
+ ++count;
+ }
+
+ DLIB_TEST(count == 20000);
+ DLIB_TEST(test2.size() == 20000);
+
+
+ while (test2.size()>0)
+ {
+ test2.remove_any(b);
+ }
+
+ DLIB_TEST(test2.size() == 0);
+ delete [] array;
+ }
+
+ test.clear();
+ test2.clear();
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ if (count == 5000)
+ break;
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ test.reset();
+
+ count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ DLIB_TEST(count == 10000);
+
+
+ test.clear();
+ test2.clear();
+ }
+
+
+ {
+ test.clear();
+ DLIB_TEST(test.size() == 0);
+ int a = 5;
+ test.add(a);
+ a = 7;
+ test.add(a);
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test.is_member(7));
+ DLIB_TEST(test.is_member(5));
+ test.destroy(7);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(!test.is_member(7));
+ DLIB_TEST(test.is_member(5));
+ test.destroy(5);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(!test.is_member(7));
+ DLIB_TEST(!test.is_member(5));
+ }
+
+ }
+
+
+
+
+ class hash_set_tester : public tester
+ {
+ public:
+ hash_set_tester (
+ ) :
+ tester ("test_hash_set",
+ "Runs tests on the hash_set component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ hash_set_kernel_test<hash_set<int,14>::kernel_1a>();
+ dlog << LINFO << "testing kernel_1a_c";
+ hash_set_kernel_test<hash_set<int,14>::kernel_1a_c>();
+ dlog << LINFO << "testing kernel_1b";
+ hash_set_kernel_test<hash_set<int,14>::kernel_1b>();
+ dlog << LINFO << "testing kernel_1b_c";
+ hash_set_kernel_test<hash_set<int,14>::kernel_1b_c>();
+ dlog << LINFO << "testing kernel_1c";
+ hash_set_kernel_test<hash_set<int,14>::kernel_1c>();
+ dlog << LINFO << "testing kernel_1c_c";
+ hash_set_kernel_test<hash_set<int,14>::kernel_1c_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/hash_table.cpp b/ml/dlib/dlib/test/hash_table.cpp
new file mode 100644
index 000000000..f4754835e
--- /dev/null
+++ b/ml/dlib/dlib/test/hash_table.cpp
@@ -0,0 +1,663 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/hash_table.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.hash_table");
+
+ template <
+ typename hash_table
+ >
+ void hash_table_kernel_test (
+ )
+ /*!
+ requires
+ - hash_table is an implementation of hash_table/hash_table_kernel_abstract.h
+ and is instantiated to map ints to ints
+ ensures
+ - runs tests on hash_table for compliance with the specs
+ !*/
+ {
+
+ srand(static_cast<unsigned int>(time(0)));
+
+
+
+
+ {
+ hash_table test(16);
+
+ DLIB_TEST(test.count(3) == 0);
+
+ enumerable<map_pair<int,int> >& e = test;
+ DLIB_TEST(e.at_start() == true);
+
+ hash_table test2(16);
+
+ hash_table test3(0);
+ hash_table test4(0);
+
+
+ print_spinner();
+
+ int b;
+ for (int j = 0; j < 4; ++j)
+ {
+ int a = 4;
+ b = 5;
+ test2.add(a,b);
+ DLIB_TEST(test2.size() == 1);
+ DLIB_TEST(*test2[4] == 5);
+ DLIB_TEST(test2[99] == 0);
+
+ DLIB_TEST(test2.move_next());
+ DLIB_TEST(test2.element().key() == 4);
+ DLIB_TEST(test2.element().value() == 5);
+
+ swap(test,test2);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(*test[4] == 5);
+ DLIB_TEST(test[99] == 0);
+
+ test.swap(test2);
+
+ a = 99;
+ b = 35;
+ test2.add(a,b);
+ DLIB_TEST(test2.size() == 2);
+ DLIB_TEST(*test2[4] == 5);
+ DLIB_TEST(*test2[99] == 35);
+ DLIB_TEST(test2[99] != 0);
+ DLIB_TEST(test2[949] == 0);
+
+ test2.destroy(4);
+ DLIB_TEST(test2.size() == 1);
+ DLIB_TEST(test2[4] == 0);
+ DLIB_TEST(*test2[99] == 35);
+ DLIB_TEST(test2[99] != 0);
+ DLIB_TEST(test2[949] == 0);
+
+
+
+ test2.destroy(99);
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2[4] == 0);
+ DLIB_TEST(test2[99] == 0);
+ DLIB_TEST(test2[949] == 0);
+
+
+
+ test2.clear();
+ }
+
+
+ print_spinner();
+
+
+
+
+ for (int j = 0; j < 4; ++j)
+ {
+
+ DLIB_TEST(test.count(3) == 0);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+
+ int a;
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand()%1000;
+ int temp = a;
+ unsigned long count = test.count(a);
+ test.add(a,b);
+ DLIB_TEST(test.count(temp) == count+1);
+ }
+
+ {
+ unsigned long count = test.count(3);
+
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ }
+
+
+ test.clear();
+
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = b = i;
+ unsigned long count = test.count(a);
+ test.add(a,b);
+ DLIB_TEST(test.count(i) == count+1);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.current_element_valid() == true);
+
+
+ test.reset();
+
+ DLIB_TEST(test.size() == 10000);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ if (test.size() > 0)
+ {
+ int* array = new int[test.size()];
+ int* tmp = array;
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ *tmp = test.element().key();
+ DLIB_TEST(test[*tmp] != 0);
+ DLIB_TEST(*tmp == test.element().key());
+ DLIB_TEST(*tmp == test.element().value());
+ DLIB_TEST(*tmp == test.element().key());
+ DLIB_TEST(test.current_element_valid() == true);
+ ++tmp;
+ }
+
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ DLIB_TEST(test.size() == 10000);
+
+ swap(test,test2);
+
+
+
+
+ // serialize the state of test2, then clear test2, then
+ // load the state back into test2.
+ ostringstream sout;
+ serialize(test2,sout);
+ DLIB_TEST(test2.at_start() == true);
+ istringstream sin(sout.str());
+ test2.clear();
+ deserialize(test2,sin);
+ DLIB_TEST(test2.at_start() == true);
+
+
+
+
+ tmp = array;
+ for (int i = 0; i < 10000; ++i)
+ {
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ ++tmp;
+ }
+
+ test2.swap(test);
+ test.reset();
+
+ DLIB_TEST(test.at_start() == true);
+ count = 0;
+ tmp = array;
+ while (test.size() > 0)
+ {
+ test.remove(*tmp,a,b);
+
+ ++tmp;
+ ++count;
+ }
+
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test.size() == 0);
+
+
+
+ DLIB_TEST(count == 10000);
+
+
+
+
+
+
+
+ delete [] array;
+ }
+
+ test.move_next();
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand();
+ test.add(a,b);
+ }
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.move_next() == true);
+
+ DLIB_TEST(test.size() == 10000);
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ test.remove_any(a,b);
+ }
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.size() == 0);
+
+ test.clear();
+
+
+
+
+
+
+
+
+
+ int* dtmp = new int[10000];
+ int* rtmp = new int[10000];
+
+ int* d = dtmp;
+ int* r = rtmp;
+ for (unsigned long i = 0; i < 10000; ++i)
+ {
+ a = ::rand();
+ b = ::rand();
+ *d = a;
+ *r = b;
+ if (test[a] != 0)
+ {
+ --i;
+ continue;
+ }
+ test.add(a,b);
+ ++d;
+ ++r;
+ DLIB_TEST(test.size() == i+1);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ DLIB_TEST(*test[dtmp[i]] == rtmp[i]);
+ }
+
+
+ delete [] dtmp;
+ delete [] rtmp;
+
+ test.clear();
+ }}
+
+
+ print_spinner();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ // now do the same thing as above but with a much smaller hash table
+ {
+ hash_table test(13);
+
+ DLIB_TEST(test.count(3) == 0);
+
+ enumerable<map_pair<int,int> >& e = test;
+ DLIB_TEST(e.at_start() == true);
+
+ hash_table test2(16);
+
+ hash_table test3(0);
+ hash_table test4(0);
+
+
+ int b;
+ for (int j = 0; j < 4; ++j)
+ {
+ int a = 4;
+ b = 5;
+ test2.add(a,b);
+ DLIB_TEST(test2.size() == 1);
+ DLIB_TEST(*test2[4] == 5);
+ DLIB_TEST(test2[99] == 0);
+
+
+ DLIB_TEST(test2.move_next());
+ DLIB_TEST(test2.element().key() == 4);
+ DLIB_TEST(test2.element().value() == 5);
+
+ swap(test,test2);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(*test[4] == 5);
+ DLIB_TEST(test[99] == 0);
+
+ test.swap(test2);
+
+ a = 99;
+ b = 35;
+ test2.add(a,b);
+ DLIB_TEST(test2.size() == 2);
+ DLIB_TEST(*test2[4] == 5);
+ DLIB_TEST(*test2[99] == 35);
+ DLIB_TEST(test2[99] != 0);
+ DLIB_TEST(test2[949] == 0);
+
+ test2.destroy(4);
+ DLIB_TEST(test2.size() == 1);
+ DLIB_TEST(test2[4] == 0);
+ DLIB_TEST(*test2[99] == 35);
+ DLIB_TEST(test2[99] != 0);
+ DLIB_TEST(test2[949] == 0);
+
+
+
+ test2.destroy(99);
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2[4] == 0);
+ DLIB_TEST(test2[99] == 0);
+ DLIB_TEST(test2[949] == 0);
+
+
+
+ test2.clear();
+ }
+
+
+ print_spinner();
+
+
+
+
+ for (int j = 0; j < 4; ++j)
+ {
+
+ DLIB_TEST(test.count(3) == 0);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+
+ int a;
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand()%1000;
+ int temp = a;
+ unsigned long count = test.count(a);
+ test.add(a,b);
+ DLIB_TEST(test.count(temp) == count+1);
+ }
+
+ {
+ unsigned long count = test.count(3);
+
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ a = 3; test.add(a,b); ++count;
+ DLIB_TEST(test.count(3) == count);
+ }
+
+
+ test.clear();
+
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = b = i;
+ unsigned long count = test.count(a);
+ test.add(a,b);
+ DLIB_TEST(test.count(i) == count+1);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.current_element_valid() == true);
+
+
+ test.reset();
+
+ DLIB_TEST(test.size() == 10000);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ if (test.size() > 0)
+ {
+ int* array = new int[test.size()];
+ int* tmp = array;
+
+ int count = 0;
+ while (test.move_next())
+ {
+ ++count;
+ *tmp = test.element().key();
+ DLIB_TEST(test[*tmp] != 0);
+ DLIB_TEST(*tmp == test.element().key());
+ DLIB_TEST(*tmp == test.element().value());
+ DLIB_TEST(*tmp == test.element().key());
+ DLIB_TEST(test.current_element_valid() == true);
+ ++tmp;
+ }
+
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ DLIB_TEST(test.size() == 10000);
+
+ swap(test,test2);
+
+ tmp = array;
+ for (int i = 0; i < 10000; ++i)
+ {
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ DLIB_TEST(*test2[*tmp] == *tmp);
+ ++tmp;
+ }
+
+ test2.swap(test);
+ test.reset();
+
+ DLIB_TEST(test.at_start() == true);
+ count = 0;
+ tmp = array;
+ while (test.size() > 0)
+ {
+ test.remove(*tmp,a,b);
+
+ ++tmp;
+ ++count;
+ }
+
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test.size() == 0);
+
+
+
+ DLIB_TEST(count == 10000);
+
+
+
+
+
+
+
+ delete [] array;
+ }
+
+ test.move_next();
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand();
+ test.add(a,b);
+ }
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.move_next() == true);
+
+ DLIB_TEST(test.size() == 10000);
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ test.remove_any(a,b);
+ }
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.size() == 0);
+
+ test.clear();
+
+
+
+
+
+
+
+
+ int* dtmp = new int[10000];
+ int* rtmp = new int[10000];
+
+ int* d = dtmp;
+ int* r = rtmp;
+ for (unsigned long i = 0; i < 10000; ++i)
+ {
+ a = ::rand();
+ b = ::rand();
+ *d = a;
+ *r = b;
+ if (test[a] != 0)
+ {
+ --i;
+ continue;
+ }
+ test.add(a,b);
+ ++d;
+ ++r;
+ DLIB_TEST(test.size() == i+1);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ DLIB_TEST(*test[dtmp[i]] == rtmp[i]);
+ }
+
+
+ delete [] dtmp;
+ delete [] rtmp;
+
+ test.clear();
+ }}
+
+ }
+
+
+
+
+ class hash_table_tester : public tester
+ {
+ public:
+ hash_table_tester (
+ ) :
+ tester ("test_hash_table",
+ "Runs tests on the hash_table component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ hash_table_kernel_test<hash_table<int,int>::kernel_1a> ();
+ dlog << LINFO << "testing kernel_1a_c";
+ hash_table_kernel_test<hash_table<int,int>::kernel_1a_c>();
+ dlog << LINFO << "testing kernel_2a";
+ hash_table_kernel_test<hash_table<int,int>::kernel_2a> ();
+ dlog << LINFO << "testing kernel_2a_c";
+ hash_table_kernel_test<hash_table<int,int>::kernel_2a_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/hog_image.cpp b/ml/dlib/dlib/test/hog_image.cpp
new file mode 100644
index 000000000..615e4d2ff
--- /dev/null
+++ b/ml/dlib/dlib/test/hog_image.cpp
@@ -0,0 +1,126 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/image_keypoint.h>
+#include <dlib/array2d.h>
+#include <dlib/rand.h>
+#include <dlib/pixel.h>
+#include <dlib/image_transforms.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.hog_image");
+
+// ----------------------------------------------------------------------------------------
+
+ class test_hog_image : public tester
+ {
+ public:
+ test_hog_image (
+ ) :
+ tester ("test_hog_image",
+ "Runs tests on the hog_image object.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ array2d<unsigned char> img;
+ img.set_size(200,200);
+
+ assign_all_pixels(img, 0);
+
+ hog_image<3,3,1,4,hog_signed_gradient,hog_full_interpolation> hog1, hog1_deserialized;
+ hog_image<4,4,2,4,hog_signed_gradient,hog_full_interpolation> hog2;
+
+ hog1.load(img);
+ hog2.load(img);
+
+
+ // Just test all the coordinate mapping functions.
+
+ DLIB_TEST(hog1.get_block_rect(0,0).width() == 3*3);
+ DLIB_TEST(hog1.get_block_rect(0,0).height() == 3*3);
+ DLIB_TEST(hog2.get_block_rect(0,0).width() == 4*4);
+ DLIB_TEST(hog2.get_block_rect(0,0).height() == 4*4);
+
+ DLIB_TEST(get_rect(img).contains(hog1.get_block_rect(0,0)));
+ DLIB_TEST(get_rect(img).contains(hog1.get_block_rect(hog1.nr()-1,hog1.nc()-1)));
+ DLIB_TEST(get_rect(img).contains(hog2.get_block_rect(0,0)));
+ DLIB_TEST(get_rect(img).contains(hog2.get_block_rect(hog2.nr()-1,hog2.nc()-1)));
+
+ dlib::rand rnd;
+ for (int i = 0; i < 20000; ++i)
+ {
+ point p(rnd.get_random_16bit_number(), rnd.get_random_16bit_number());
+ p.x() -= 20000;
+ p.y() -= 20000;
+
+ DLIB_TEST((hog1.feat_to_image_space(hog1.image_to_feat_space(p)) - p).length() <= 3);
+ DLIB_TEST((hog2.feat_to_image_space(hog2.image_to_feat_space(p)) - p).length() <= 10);
+
+ DLIB_TEST_MSG((hog1.image_to_feat_space(hog1.feat_to_image_space(p)) - p).length() <= 3,
+ p << " " << hog1.feat_to_image_space(p) << " " << hog1.image_to_feat_space(hog1.feat_to_image_space(p)) );
+ DLIB_TEST((hog2.image_to_feat_space(hog2.feat_to_image_space(p)) - p).length() <= 10);
+ }
+
+
+ DLIB_TEST(hog1.feat_to_image_space(point(0,0)) == point(5,5));
+ DLIB_TEST(hog2.feat_to_image_space(point(0,0)) == point(9,9));
+
+ DLIB_TEST(hog1.feat_to_image_space(point(1,1)) == point(8,8));
+ DLIB_TEST(hog2.feat_to_image_space(point(1,1)) == point(17,17));
+
+ DLIB_TEST(hog1.image_to_feat_space(hog1.feat_to_image_space(point(0,0))) == point(0,0));
+ DLIB_TEST(hog2.image_to_feat_space(hog2.feat_to_image_space(point(0,0))) == point(0,0));
+ DLIB_TEST(hog1.image_to_feat_space(hog1.feat_to_image_space(point(1,1))) == point(1,1));
+ DLIB_TEST(hog2.image_to_feat_space(hog2.feat_to_image_space(point(1,1))) == point(1,1));
+ DLIB_TEST(hog1.image_to_feat_space(hog1.feat_to_image_space(point(1,2))) == point(1,2));
+ DLIB_TEST(hog2.image_to_feat_space(hog2.feat_to_image_space(point(1,2))) == point(1,2));
+
+
+
+ DLIB_TEST(hog1_deserialized.size() != hog1.size());
+ DLIB_TEST(hog1_deserialized.nr() != hog1.nr());
+ DLIB_TEST(hog1_deserialized.nc() != hog1.nc());
+ ostringstream sout;
+ serialize(hog1, sout);
+ istringstream sin(sout.str());
+ deserialize(hog1_deserialized, sin);
+
+ DLIB_TEST(hog1_deserialized.size() == hog1.size());
+ DLIB_TEST(hog1_deserialized.nr() == hog1.nr());
+ DLIB_TEST(hog1_deserialized.nc() == hog1.nc());
+ DLIB_TEST(hog1_deserialized(0,2) == hog1(0,2));
+ DLIB_TEST(hog1_deserialized.get_block_rect(1,2) == hog1.get_block_rect(1,2));
+ DLIB_TEST(hog1_deserialized.image_to_feat_space(hog1_deserialized.feat_to_image_space(point(0,0))) == point(0,0));
+ DLIB_TEST(hog1_deserialized.image_to_feat_space(hog1_deserialized.feat_to_image_space(point(1,1))) == point(1,1));
+ DLIB_TEST(hog1_deserialized.image_to_feat_space(hog1_deserialized.feat_to_image_space(point(1,2))) == point(1,2));
+
+
+
+ DLIB_TEST(hog1.size() > 1);
+ DLIB_TEST(hog1.nr() > 1);
+ DLIB_TEST(hog1.nc() > 1);
+ hog1.clear();
+ DLIB_TEST(hog1.size() == 0);
+ DLIB_TEST(hog1.nr() == 0);
+ DLIB_TEST(hog1.nc() == 0);
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/image.cpp b/ml/dlib/dlib/test/image.cpp
new file mode 100644
index 000000000..01f1410cf
--- /dev/null
+++ b/ml/dlib/dlib/test/image.cpp
@@ -0,0 +1,1903 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/pixel.h>
+#include <dlib/array2d.h>
+#include <dlib/image_transforms.h>
+#include <dlib/image_io.h>
+#include <dlib/matrix.h>
+#include <dlib/rand.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.image");
+
+
+ void image_test (
+ )
+ /*!
+ ensures
+ - runs tests on pixel objects and functions for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ array2d<unsigned char> img1, img2;
+
+ img1.set_size(100,100);
+
+ assign_all_pixels(img1,7);
+
+ assign_image(img2, img1);
+
+ DLIB_TEST_MSG(img1.nr() == 100 && img1.nc() == 100 &&
+ img2.nr() == 100 && img2.nc() == 100,"");
+
+
+ for (long r = 0; r < img1.nr(); ++r)
+ {
+ for (long c = 0; c < img1.nc(); ++c)
+ {
+ DLIB_TEST(img1[r][c] == 7);
+ DLIB_TEST(img2[r][c] == 7);
+ }
+ }
+
+ img2.clear();
+ DLIB_TEST(img2.size() == 0);
+ DLIB_TEST(img2.nr() == 0);
+ DLIB_TEST(img2.nc() == 0);
+ assign_image(img2, mat(img1));
+
+ DLIB_TEST_MSG(img1.nr() == 100 && img1.nc() == 100 &&
+ img2.nr() == 100 && img2.nc() == 100,"");
+
+
+ for (long r = 0; r < img1.nr(); ++r)
+ {
+ for (long c = 0; c < img1.nc(); ++c)
+ {
+ DLIB_TEST(img1[r][c] == 7);
+ DLIB_TEST(img2[r][c] == 7);
+ }
+ }
+
+
+ threshold_image(img1, img2, 4);
+
+ for (long r = 0; r < img1.nr(); ++r)
+ {
+ for (long c = 0; c < img1.nc(); ++c)
+ {
+ DLIB_TEST(img1[r][c] == 7);
+ DLIB_TEST(img2[r][c] == on_pixel);
+ }
+ }
+
+ {
+ array2d<hsi_pixel> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c].h = static_cast<unsigned char>(r*14 + c + 1);
+ img[r][c].s = static_cast<unsigned char>(r*14 + c + 2);
+ img[r][c].i = static_cast<unsigned char>(r*14 + c + 3);
+ }
+ }
+
+ ostringstream sout;
+ save_dng(img, sout);
+ istringstream sin(sout.str());
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_dng(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c].h == r*14 + c + 1);
+ DLIB_TEST(img[r][c].s == r*14 + c + 2);
+ DLIB_TEST(img[r][c].i == r*14 + c + 3);
+ }
+ }
+ }
+
+
+
+
+ {
+ array2d<rgb_alpha_pixel> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c].red = static_cast<unsigned char>(r*14 + c + 1);
+ img[r][c].green = static_cast<unsigned char>(r*14 + c + 2);
+ img[r][c].blue = static_cast<unsigned char>(r*14 + c + 3);
+ img[r][c].alpha = static_cast<unsigned char>(r*14 + c + 4);
+ }
+ }
+
+ ostringstream sout;
+ save_dng(img, sout);
+ istringstream sin(sout.str());
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_dng(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c].red == r*14 + c + 1);
+ DLIB_TEST(img[r][c].green == r*14 + c + 2);
+ DLIB_TEST(img[r][c].blue == r*14 + c + 3);
+ DLIB_TEST(img[r][c].alpha == r*14 + c + 4);
+ }
+ }
+ }
+
+#ifdef DLIB_PNG_SUPPORT
+ {
+ array2d<rgb_alpha_pixel> img;
+ array2d<rgb_pixel> img2, img3;
+ img.set_size(14,15);
+ img2.set_size(img.nr(),img.nc());
+ img3.set_size(img.nr(),img.nc());
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c].red = static_cast<unsigned char>(r*14 + c + 1);
+ img[r][c].green = static_cast<unsigned char>(r*14 + c + 2);
+ img[r][c].blue = static_cast<unsigned char>(r*14 + c + 3);
+ img[r][c].alpha = static_cast<unsigned char>(r*14 + c + 4);
+ }
+ }
+
+ save_png(img, "test.png");
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_png(img, "test.png");
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ assign_all_pixels(img2, 255);
+ assign_all_pixels(img3, 0);
+ load_png(img2, "test.png");
+ assign_image(img3, img);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c].red == r*14 + c + 1);
+ DLIB_TEST(img[r][c].green == r*14 + c + 2);
+ DLIB_TEST(img[r][c].blue == r*14 + c + 3);
+ DLIB_TEST(img[r][c].alpha == r*14 + c + 4);
+
+ DLIB_TEST(img2[r][c].red == img3[r][c].red);
+ DLIB_TEST(img2[r][c].green == img3[r][c].green);
+ DLIB_TEST(img2[r][c].blue == img3[r][c].blue);
+ }
+ }
+ }
+#endif // DLIB_PNG_SUPPORT
+
+
+
+ {
+ array2d<rgb_pixel> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c].red = static_cast<unsigned char>(r*14 + c + 1);
+ img[r][c].green = static_cast<unsigned char>(r*14 + c + 2);
+ img[r][c].blue = static_cast<unsigned char>(r*14 + c + 3);
+ }
+ }
+
+ ostringstream sout;
+ save_dng(img, sout);
+ save_bmp(img, sout);
+ save_dng(img, sout);
+ save_bmp(img, sout);
+ istringstream sin(sout.str());
+
+ for (int i = 0; i < 2; ++i)
+ {
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_dng(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c].red == r*14 + c + 1);
+ DLIB_TEST(img[r][c].green == r*14 + c + 2);
+ DLIB_TEST(img[r][c].blue == r*14 + c + 3);
+ }
+ }
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_bmp(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST_MSG(img[r][c].red == r*14 + c + 1, "got " << (int)img[r][c].red << " but expected " << r*14 + c + 1);
+ DLIB_TEST(img[r][c].green == r*14 + c + 2);
+ DLIB_TEST(img[r][c].blue == r*14 + c + 3);
+ }
+ }
+ }
+ }
+ {
+ array2d<bgr_pixel> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c].red = static_cast<unsigned char>(r*14 + c + 1);
+ img[r][c].green = static_cast<unsigned char>(r*14 + c + 2);
+ img[r][c].blue = static_cast<unsigned char>(r*14 + c + 3);
+ }
+ }
+
+ ostringstream sout;
+ save_dng(img, sout);
+ save_bmp(img, sout);
+ save_dng(img, sout);
+ save_bmp(img, sout);
+ istringstream sin(sout.str());
+
+ for (int i = 0; i < 2; ++i)
+ {
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_dng(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c].red == r*14 + c + 1);
+ DLIB_TEST(img[r][c].green == r*14 + c + 2);
+ DLIB_TEST(img[r][c].blue == r*14 + c + 3);
+ }
+ }
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_bmp(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST_MSG(img[r][c].red == r*14 + c + 1, "got " << (int)img[r][c].red << " but expected " << r*14 + c + 1);
+ DLIB_TEST(img[r][c].green == r*14 + c + 2);
+ DLIB_TEST(img[r][c].blue == r*14 + c + 3);
+ }
+ }
+ }
+ }
+
+#ifdef DLIB_PNG_SUPPORT
+ {
+ array2d<rgb_pixel> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c].red = static_cast<unsigned char>(r*14 + c + 1);
+ img[r][c].green = static_cast<unsigned char>(r*14 + c + 2);
+ img[r][c].blue = static_cast<unsigned char>(r*14 + c + 3);
+ }
+ }
+
+ save_png(img, "test.png");
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_png(img, "test.png");
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c].red == r*14 + c + 1);
+ DLIB_TEST(img[r][c].green == r*14 + c + 2);
+ DLIB_TEST(img[r][c].blue == r*14 + c + 3);
+ }
+ }
+ }
+ {
+ array2d<bgr_pixel> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c].red = static_cast<unsigned char>(r*14 + c + 1);
+ img[r][c].green = static_cast<unsigned char>(r*14 + c + 2);
+ img[r][c].blue = static_cast<unsigned char>(r*14 + c + 3);
+ }
+ }
+
+ save_png(img, "test.png");
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_png(img, "test.png");
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c].red == r*14 + c + 1);
+ DLIB_TEST(img[r][c].green == r*14 + c + 2);
+ DLIB_TEST(img[r][c].blue == r*14 + c + 3);
+ }
+ }
+ }
+#endif // DLIB_PNG_SUPPORT
+
+
+
+ {
+ array2d<unsigned short> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c] = static_cast<unsigned short>(r*14 + c + 0xF0);
+ }
+ }
+
+ ostringstream sout;
+ save_dng(img, sout);
+ istringstream sin(sout.str());
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_dng(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c] == r*14 + c + 0xF0);
+ }
+ }
+ }
+
+
+#ifdef DLIB_PNG_SUPPORT
+ {
+ array2d<unsigned short> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c] = static_cast<unsigned short>(r*14 + c + 0xF0);
+ }
+ }
+
+ save_png(img, "test.png");
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_png(img, "test.png");
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c] == r*14 + c + 0xF0);
+ }
+ }
+ }
+#endif // DLIB_PNG_SUPPORT
+
+
+
+ {
+ array2d<unsigned char> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c] = static_cast<unsigned char>(r*14 + c*111);
+ }
+ }
+
+ ostringstream sout;
+ save_dng(img, sout);
+ save_bmp(img, sout);
+ save_dng(img, sout);
+ save_bmp(img, sout);
+ istringstream sin(sout.str());
+
+ for (int i = 0; i < 2; ++i)
+ {
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_dng(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c] == static_cast<unsigned char>(r*14 + c*111));
+ }
+ }
+
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_bmp(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c] == static_cast<unsigned char>(r*14 + c*111));
+ }
+ }
+ }
+ }
+
+
+#ifdef DLIB_PNG_SUPPORT
+ {
+ array2d<unsigned char> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c] = static_cast<unsigned char>(r*14 + c);
+ }
+ }
+
+ save_png(img, "test.png");
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_png(img, "test.png");
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c] == r*14 + c);
+ }
+ }
+
+ }
+#endif // DLIB_PNG_SUPPORT
+
+
+ {
+ // in this test we will only assign pixel values that can be
+ // represented with 8 bits even though we are using a wider pixel type.
+ array2d<unsigned short> img;
+ img.set_size(14,15);
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ img[r][c] = static_cast<unsigned char>(r*14 + c);
+ }
+ }
+
+ ostringstream sout;
+ save_dng(img, sout);
+ save_bmp(img, sout);
+ save_dng(img, sout);
+ save_bmp(img, sout);
+ istringstream sin(sout.str());
+
+ for (int i = 0; i < 2; ++i)
+ {
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_dng(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c] == r*14 + c);
+ }
+ }
+
+
+ img.clear();
+ DLIB_TEST(img.nr() == 0);
+ DLIB_TEST(img.nc() == 0);
+
+ load_bmp(img, sin);
+
+ DLIB_TEST(img.nr() == 14);
+ DLIB_TEST(img.nc() == 15);
+
+ for (long r = 0; r < 14; ++r)
+ {
+ for (long c = 0; c < 15; ++c)
+ {
+ DLIB_TEST(img[r][c] == r*14 + c);
+ }
+ }
+ }
+ }
+
+ {
+ array2d<unsigned short> img1;
+ array2d<unsigned char> img2;
+ img1.set_size(10,10);
+ assign_all_pixels(img1, 0);
+
+ img1[5][5] = 10000;
+ img1[7][7] = 10000;
+
+ equalize_histogram(img1, img2);
+
+ for (long r = 0; r < img1.nr(); ++r)
+ {
+ for (long c = 0; c < img2.nc(); ++c)
+ {
+ if ((r == 5 && c == 5) ||
+ (r == 7 && c == 7))
+ {
+ DLIB_TEST(img2[r][c] == 255);
+ }
+ else
+ {
+ DLIB_TEST(img2[r][c] == 0);
+ }
+ }
+ }
+
+ }
+
+ {
+ array2d<unsigned char> img;
+ img.set_size(10,10);
+ assign_all_pixels(img, 0);
+
+ assign_border_pixels(img, 2,2, 4);
+
+ DLIB_TEST(zeros_matrix<unsigned char>(6,6) == subm(mat(img), rectangle(2,2,7,7)));
+ DLIB_TEST(uniform_matrix<unsigned char>(1,10, 4) == rowm(mat(img), 0));
+ DLIB_TEST(uniform_matrix<unsigned char>(1,10, 4) == rowm(mat(img), 1));
+ DLIB_TEST(uniform_matrix<unsigned char>(1,10, 4) == rowm(mat(img), 8));
+ DLIB_TEST(uniform_matrix<unsigned char>(1,10, 4) == rowm(mat(img), 9));
+
+ DLIB_TEST(uniform_matrix<unsigned char>(10,1, 4) == colm(mat(img), 0));
+ DLIB_TEST(uniform_matrix<unsigned char>(10,1, 4) == colm(mat(img), 1));
+ DLIB_TEST(uniform_matrix<unsigned char>(10,1, 4) == colm(mat(img), 8));
+ DLIB_TEST(uniform_matrix<unsigned char>(10,1, 4) == colm(mat(img), 9));
+
+
+ assign_border_pixels(img, 7, 7, 5);
+ DLIB_TEST(uniform_matrix<unsigned char>(10,10, 5) == mat(img));
+ assign_border_pixels(img, 37, 47, 5);
+ DLIB_TEST(uniform_matrix<unsigned char>(10,10, 5) == mat(img));
+ }
+
+ {
+ array2d<unsigned char> img;
+ img.set_size(11,11);
+ assign_all_pixels(img, 0);
+
+ assign_border_pixels(img, 2,2, 4);
+
+ DLIB_TEST(zeros_matrix<unsigned char>(7,7) == subm(mat(img), rectangle(2,2,8,8)));
+ DLIB_TEST(uniform_matrix<unsigned char>(1,11, 4) == rowm(mat(img), 0));
+ DLIB_TEST(uniform_matrix<unsigned char>(1,11, 4) == rowm(mat(img), 1));
+ DLIB_TEST(uniform_matrix<unsigned char>(1,11, 4) == rowm(mat(img), 9));
+ DLIB_TEST(uniform_matrix<unsigned char>(1,11, 4) == rowm(mat(img), 10));
+
+ DLIB_TEST(uniform_matrix<unsigned char>(11,1, 4) == colm(mat(img), 0));
+ DLIB_TEST(uniform_matrix<unsigned char>(11,1, 4) == colm(mat(img), 1));
+ DLIB_TEST(uniform_matrix<unsigned char>(11,1, 4) == colm(mat(img), 9));
+ DLIB_TEST(uniform_matrix<unsigned char>(11,1, 4) == colm(mat(img), 10));
+
+ assign_border_pixels(img, 7, 7, 5);
+ DLIB_TEST(uniform_matrix<unsigned char>(11,11, 5) == mat(img));
+ assign_border_pixels(img, 70, 57, 5);
+ DLIB_TEST(uniform_matrix<unsigned char>(11,11, 5) == mat(img));
+ }
+
+
+ }
+
+
+ template <typename T, typename pixel_type>
+ void test_integral_image (
+ )
+ {
+ dlib::rand rnd;
+
+ array2d<pixel_type> img;
+ integral_image_generic<T> int_img;
+
+ int_img.load(img);
+ DLIB_TEST(int_img.nr() == 0);
+ DLIB_TEST(int_img.nc() == 0);
+
+ // make 5 random images
+ for (int i = 0; i < 5; ++i)
+ {
+ print_spinner();
+ img.set_size(rnd.get_random_16bit_number()%200+1, rnd.get_random_16bit_number()%200+1);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ img[r][c] = (int)rnd.get_random_8bit_number() - 100;
+ }
+ }
+
+ int_img.load(img);
+ DLIB_TEST(int_img.nr() == img.nr());
+ DLIB_TEST(int_img.nc() == img.nc());
+
+ // make 200 random rectangles
+ for (int j = 0; j < 500; ++j)
+ {
+ point p1(rnd.get_random_32bit_number()%img.nc(), rnd.get_random_32bit_number()%img.nr());
+ point p2(rnd.get_random_32bit_number()%img.nc(), rnd.get_random_32bit_number()%img.nr());
+ rectangle rect(p1,p2);
+ DLIB_TEST(int_img.get_sum_of_area(rect) == sum(subm(matrix_cast<T>(mat(img)), rect)));
+ rect = rectangle(p1,p1);
+ DLIB_TEST(int_img.get_sum_of_area(rect) == sum(subm(matrix_cast<T>(mat(img)), rect)));
+ }
+
+ }
+
+
+ }
+
+ void test_filtering2(int nr, int nc, dlib::rand& rnd)
+ {
+ print_spinner();
+ dlog << LINFO << "test_filtering2(): " << nr << " " << nc;
+ array2d<float> img(302,301);
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ img[r][c] = rnd.get_random_gaussian();
+ }
+ }
+ matrix<float> filt = matrix_cast<float>(randm(nr,nc,rnd));
+
+ matrix<float> out = xcorr_same(mat(img),filt);
+ matrix<float> out2 = subm(conv(mat(img),flip(filt)), filt.nr()/2, filt.nc()/2, img.nr(), img.nc());
+ // make sure xcorr_same does exactly what the docs say it should.
+ DLIB_TEST(max(abs(out-out2)) < 1e-7);
+
+ // Now compare the filtering functions to xcorr_same to make sure everything does
+ // filtering in the same way.
+ array2d<float> imout(img.nr(), img.nc());
+ assign_all_pixels(imout, 10);
+ rectangle rect = spatially_filter_image(img, imout, filt);
+ border_enumerator be(get_rect(imout),rect);
+ while (be.move_next())
+ {
+ DLIB_TEST(imout[be.element().y()][be.element().x()] == 0);
+ }
+ DLIB_TEST_MSG(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-5, max(abs(subm(mat(imout),rect) - subm(out,rect))));
+
+
+ assign_all_pixels(imout, 10);
+ out = 10;
+ rect = spatially_filter_image(img, imout, filt,2,true,true);
+ be = border_enumerator(get_rect(imout),rect);
+ while (be.move_next())
+ {
+ DLIB_TEST(imout[be.element().y()][be.element().x()] == 10);
+ }
+ out += abs(xcorr_same(mat(img),filt)/2);
+ DLIB_TEST(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-7);
+
+
+ assign_all_pixels(imout, -10);
+ out = -10;
+ rect = spatially_filter_image(img, imout, filt,2,false,true);
+ be = border_enumerator(get_rect(imout),rect);
+ while (be.move_next())
+ {
+ DLIB_TEST(imout[be.element().y()][be.element().x()] == -10);
+ }
+ out += xcorr_same(mat(img),filt)/2;
+ DLIB_TEST_MSG(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-5, max(abs(subm(mat(imout),rect) - subm(out,rect))));
+
+
+
+
+ matrix<float> row_filt = matrix_cast<float>(randm(nc,1,rnd));
+ matrix<float> col_filt = matrix_cast<float>(randm(nr,1,rnd));
+ assign_all_pixels(imout, 10);
+ rect = spatially_filter_image_separable(img, imout, row_filt, col_filt);
+ out = xcorr_same(tmp(xcorr_same(mat(img),trans(row_filt))), col_filt);
+ DLIB_TEST_MSG(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-5, max(abs(subm(mat(imout),rect) - subm(out,rect))));
+
+ be = border_enumerator(get_rect(imout),rect);
+ while (be.move_next())
+ {
+ DLIB_TEST(imout[be.element().y()][be.element().x()] == 0);
+ }
+
+
+ assign_all_pixels(imout, 10);
+ out = 10;
+ rect = spatially_filter_image_separable(img, imout, row_filt, col_filt,2,true,true);
+ out += abs(xcorr_same(tmp(xcorr_same(mat(img),trans(row_filt))), col_filt)/2);
+ DLIB_TEST_MSG(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-7,
+ max(abs(subm(mat(imout),rect) - subm(out,rect))));
+
+ be = border_enumerator(get_rect(imout),rect);
+ while (be.move_next())
+ {
+ DLIB_TEST(imout[be.element().y()][be.element().x()] == 10);
+ }
+
+ }
+
+ template <typename T>
+ void test_filtering(bool use_abs, unsigned long scale )
+ {
+ print_spinner();
+ dlog << LINFO << "test_filtering(" << use_abs << "," << scale << ")";
+ array2d<T> img, img2, img3;
+ img.set_size(10,11);
+
+ assign_all_pixels(img, 10);
+
+ matrix<int,3,5> filter2;
+ filter2 = 1,1,1,1,1,
+ 1,1,1,1,1,
+ 1,1,1,1,1;
+
+ assign_all_pixels(img2,3);
+ rectangle brect = spatially_filter_image(img, img2, filter2);
+ DLIB_TEST(brect == shrink_rect(get_rect(img), filter2.nc()/2, filter2.nr()/2));
+
+ const rectangle rect(2,1,img.nc()-3,img.nr()-2);
+
+ for (long r = 0; r<img2.nr(); ++r)
+ {
+ for (long c = 0; c<img2.nc(); ++c)
+ {
+ if (rect.contains(c,r))
+ {
+ DLIB_TEST_MSG(img2[r][c] == 150, (int)img2[r][c]);
+ }
+ else
+ {
+ DLIB_TEST_MSG(img2[r][c] == 0,(int)img2[r][c]);
+ }
+ }
+ }
+
+
+ assign_all_pixels(img2,3);
+ assign_all_pixels(img3,3);
+ brect = spatially_filter_image(img, img2, filter2);
+ DLIB_TEST(brect == shrink_rect(get_rect(img), filter2.nc()/2, filter2.nr()/2));
+
+ matrix<int,1,5> row_filter;
+ matrix<int,1,3> col_filter;
+
+ row_filter = 1,1,1,1,1;
+ col_filter = 1,1,1;
+
+ spatially_filter_image_separable(img, img3, row_filter, col_filter);
+
+ DLIB_TEST(mat(img2) == mat(img3));
+
+
+ dlib::rand rnd;
+
+ for (int i = 0; i < 30; ++i)
+ {
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ img[r][c] = rnd.get_random_8bit_number();
+ }
+ }
+
+ row_filter(0) = ((int)rnd.get_random_8bit_number() - 100)/10;
+ row_filter(1) = ((int)rnd.get_random_8bit_number() - 100)/10;
+ row_filter(2) = ((int)rnd.get_random_8bit_number() - 100)/10;
+ row_filter(3) = ((int)rnd.get_random_8bit_number() - 100)/10;
+ row_filter(4) = ((int)rnd.get_random_8bit_number() - 100)/10;
+ col_filter(0) = ((int)rnd.get_random_8bit_number() - 100)/10;
+ col_filter(1) = ((int)rnd.get_random_8bit_number() - 100)/10;
+ col_filter(2) = ((int)rnd.get_random_8bit_number() - 100)/10;
+
+ const matrix<int,3,5> filter = trans(col_filter)*row_filter;
+
+ assign_all_pixels(img2,3);
+ assign_all_pixels(img3,3);
+ // Just make sure both filtering methods give the same results.
+ rectangle brect1, brect2;
+ brect1 = spatially_filter_image(img, img2, filter, scale, use_abs);
+ brect2 = spatially_filter_image_separable(img, img3, row_filter, col_filter, scale, use_abs);
+ DLIB_TEST(mat(img2) == mat(img3));
+
+ DLIB_TEST(brect1 == shrink_rect(get_rect(img), filter.nc()/2, filter.nr()/2));
+ DLIB_TEST(brect1 == brect2);
+ }
+
+ {
+ array2d<int> img, img2;
+ img.set_size(3,4);
+
+ matrix<int> filter(3,3);
+ filter = 1;
+ assign_all_pixels(img,-1);
+
+ spatially_filter_image(img,img2,filter);
+
+ DLIB_TEST(img2[0][0] == 0);
+ DLIB_TEST(img2[0][1] == 0);
+ DLIB_TEST(img2[0][2] == 0);
+ DLIB_TEST(img2[0][3] == 0);
+
+ DLIB_TEST(img2[1][0] == 0);
+ DLIB_TEST(img2[1][1] == -9);
+ DLIB_TEST(img2[1][2] == -9);
+ DLIB_TEST(img2[1][3] == 0);
+
+ DLIB_TEST(img2[2][0] == 0);
+ DLIB_TEST(img2[2][1] == 0);
+ DLIB_TEST(img2[2][2] == 0);
+ DLIB_TEST(img2[2][3] == 0);
+
+ assign_all_pixels(img,-1);
+
+ spatially_filter_image(img,img2,filter,2,true);
+
+ DLIB_TEST(img2[0][0] == 0);
+ DLIB_TEST(img2[0][1] == 0);
+ DLIB_TEST(img2[0][2] == 0);
+ DLIB_TEST(img2[0][3] == 0);
+
+ DLIB_TEST(img2[1][0] == 0);
+ DLIB_TEST(img2[1][1] == 4);
+ DLIB_TEST(img2[1][2] == 4);
+ DLIB_TEST(img2[1][3] == 0);
+
+ DLIB_TEST(img2[2][0] == 0);
+ DLIB_TEST(img2[2][1] == 0);
+ DLIB_TEST(img2[2][2] == 0);
+ DLIB_TEST(img2[2][3] == 0);
+
+ matrix<int> rowf(3,1), colf(3,1);
+ rowf = 1;
+ colf = 1;
+ assign_all_pixels(img,-1);
+
+ spatially_filter_image_separable(img,img2,rowf,colf);
+ DLIB_TEST(img2[0][0] == 0);
+ DLIB_TEST(img2[0][1] == 0);
+ DLIB_TEST(img2[0][2] == 0);
+ DLIB_TEST(img2[0][3] == 0);
+
+ DLIB_TEST(img2[1][0] == 0);
+ DLIB_TEST(img2[1][1] == -9);
+ DLIB_TEST(img2[1][2] == -9);
+ DLIB_TEST(img2[1][3] == 0);
+
+ DLIB_TEST(img2[2][0] == 0);
+ DLIB_TEST(img2[2][1] == 0);
+ DLIB_TEST(img2[2][2] == 0);
+ DLIB_TEST(img2[2][3] == 0);
+
+ spatially_filter_image_separable(img,img2,rowf,colf,1,true);
+ DLIB_TEST(img2[0][0] == 0);
+ DLIB_TEST(img2[0][1] == 0);
+ DLIB_TEST(img2[0][2] == 0);
+ DLIB_TEST(img2[0][3] == 0);
+
+ DLIB_TEST(img2[1][0] == 0);
+ DLIB_TEST(img2[1][1] == 9);
+ DLIB_TEST(img2[1][2] == 9);
+ DLIB_TEST(img2[1][3] == 0);
+
+ DLIB_TEST(img2[2][0] == 0);
+ DLIB_TEST(img2[2][1] == 0);
+ DLIB_TEST(img2[2][2] == 0);
+ DLIB_TEST(img2[2][3] == 0);
+
+ assign_all_pixels(img2, 3);
+ spatially_filter_image_separable(img,img2,rowf,colf,1,true, true);
+ DLIB_TEST(img2[0][0] == 3);
+ DLIB_TEST(img2[0][1] == 3);
+ DLIB_TEST(img2[0][2] == 3);
+ DLIB_TEST(img2[0][3] == 3);
+
+ DLIB_TEST(img2[1][0] == 3);
+ DLIB_TEST_MSG(img2[1][1] == 9+3, img2[1][1] );
+ DLIB_TEST(img2[1][2] == 9+3);
+ DLIB_TEST(img2[1][3] == 3);
+
+ DLIB_TEST(img2[2][0] == 3);
+ DLIB_TEST(img2[2][1] == 3);
+ DLIB_TEST(img2[2][2] == 3);
+ DLIB_TEST(img2[2][3] == 3);
+ }
+ {
+ array2d<double> img, img2;
+ img.set_size(3,4);
+
+ matrix<double> filter(3,3);
+ filter = 1;
+ assign_all_pixels(img,-1);
+
+ spatially_filter_image(img,img2,filter,2);
+
+ DLIB_TEST(img2[0][0] == 0);
+ DLIB_TEST(img2[0][1] == 0);
+ DLIB_TEST(img2[0][2] == 0);
+ DLIB_TEST(img2[0][3] == 0);
+
+ DLIB_TEST(img2[1][0] == 0);
+ DLIB_TEST(std::abs(img2[1][1] - -4.5) < 1e-14);
+ DLIB_TEST(std::abs(img2[1][2] - -4.5) < 1e-14);
+ DLIB_TEST(img2[1][3] == 0);
+
+ DLIB_TEST(img2[2][0] == 0);
+ DLIB_TEST(img2[2][1] == 0);
+ DLIB_TEST(img2[2][2] == 0);
+ DLIB_TEST(img2[2][3] == 0);
+
+ }
+ {
+ array2d<double> img, img2;
+ img.set_size(3,4);
+ img2.set_size(3,4);
+ assign_all_pixels(img2, 8);
+
+ matrix<double> filter(3,3);
+ filter = 1;
+ assign_all_pixels(img,-1);
+
+ spatially_filter_image(img,img2,filter,2, false, true);
+
+ DLIB_TEST(img2[0][0] == 8);
+ DLIB_TEST(img2[0][1] == 8);
+ DLIB_TEST(img2[0][2] == 8);
+ DLIB_TEST(img2[0][3] == 8);
+
+ DLIB_TEST(img2[1][0] == 8);
+ DLIB_TEST(std::abs(img2[1][1] - -4.5 - 8) < 1e-14);
+ DLIB_TEST(std::abs(img2[1][2] - -4.5 - 8) < 1e-14);
+ DLIB_TEST(img2[1][3] == 8);
+
+ DLIB_TEST(img2[2][0] == 8);
+ DLIB_TEST(img2[2][1] == 8);
+ DLIB_TEST(img2[2][2] == 8);
+ DLIB_TEST(img2[2][3] == 8);
+
+ }
+ }
+
+
+ void test_zero_border_pixels(
+ )
+ {
+ array2d<unsigned char> img;
+ img.set_size(4,5);
+
+ assign_all_pixels(img, 1);
+ zero_border_pixels(img, 2,1);
+
+ DLIB_TEST(img[0][0] == 0);
+ DLIB_TEST(img[1][0] == 0);
+ DLIB_TEST(img[2][0] == 0);
+ DLIB_TEST(img[3][0] == 0);
+ DLIB_TEST(img[0][1] == 0);
+ DLIB_TEST(img[1][1] == 0);
+ DLIB_TEST(img[2][1] == 0);
+ DLIB_TEST(img[3][1] == 0);
+
+ DLIB_TEST(img[0][3] == 0);
+ DLIB_TEST(img[1][3] == 0);
+ DLIB_TEST(img[2][3] == 0);
+ DLIB_TEST(img[3][3] == 0);
+ DLIB_TEST(img[0][4] == 0);
+ DLIB_TEST(img[1][4] == 0);
+ DLIB_TEST(img[2][4] == 0);
+ DLIB_TEST(img[3][4] == 0);
+
+ DLIB_TEST(img[0][2] == 0);
+ DLIB_TEST(img[3][2] == 0);
+
+ DLIB_TEST(img[1][2] == 1);
+ DLIB_TEST(img[2][2] == 1);
+
+ rectangle rect = get_rect(img);
+ rect.left()+=2;
+ rect.top()+=1;
+ rect.right()-=2;
+ rect.bottom()-=1;
+ assign_all_pixels(img, 1);
+ zero_border_pixels(img, rect);
+
+ DLIB_TEST(img[0][0] == 0);
+ DLIB_TEST(img[1][0] == 0);
+ DLIB_TEST(img[2][0] == 0);
+ DLIB_TEST(img[3][0] == 0);
+ DLIB_TEST(img[0][1] == 0);
+ DLIB_TEST(img[1][1] == 0);
+ DLIB_TEST(img[2][1] == 0);
+ DLIB_TEST(img[3][1] == 0);
+
+ DLIB_TEST(img[0][3] == 0);
+ DLIB_TEST(img[1][3] == 0);
+ DLIB_TEST(img[2][3] == 0);
+ DLIB_TEST(img[3][3] == 0);
+ DLIB_TEST(img[0][4] == 0);
+ DLIB_TEST(img[1][4] == 0);
+ DLIB_TEST(img[2][4] == 0);
+ DLIB_TEST(img[3][4] == 0);
+
+ DLIB_TEST(img[0][2] == 0);
+ DLIB_TEST(img[3][2] == 0);
+
+ DLIB_TEST(img[1][2] == 1);
+ DLIB_TEST(img[2][2] == 1);
+
+ rect.right()+=1;
+ assign_all_pixels(img, 1);
+ zero_border_pixels(img, rect);
+ DLIB_TEST(img[0][0] == 0);
+ DLIB_TEST(img[1][0] == 0);
+ DLIB_TEST(img[2][0] == 0);
+ DLIB_TEST(img[3][0] == 0);
+ DLIB_TEST(img[0][1] == 0);
+ DLIB_TEST(img[1][1] == 0);
+ DLIB_TEST(img[2][1] == 0);
+ DLIB_TEST(img[3][1] == 0);
+
+ DLIB_TEST(img[0][3] == 0);
+ DLIB_TEST(img[1][3] == 1);
+ DLIB_TEST(img[2][3] == 1);
+ DLIB_TEST(img[3][3] == 0);
+ DLIB_TEST(img[0][4] == 0);
+ DLIB_TEST(img[1][4] == 0);
+ DLIB_TEST(img[2][4] == 0);
+ DLIB_TEST(img[3][4] == 0);
+
+ DLIB_TEST(img[0][2] == 0);
+ DLIB_TEST(img[3][2] == 0);
+
+ DLIB_TEST(img[1][2] == 1);
+ DLIB_TEST(img[2][2] == 1);
+ }
+
+
+ void test_label_connected_blobs()
+ {
+ array2d<unsigned char> img;
+ img.set_size(400,401);
+
+ assign_all_pixels(img,0);
+
+ rectangle rect1, rect2, rect3;
+
+ rect1 = centered_rect(99,120, 50,70);
+ rect2 = centered_rect(199,80, 34,68);
+ rect3 = centered_rect(249,180, 120,78);
+
+ fill_rect(img, rect1, 255);
+ fill_rect(img, rect2, 255);
+ fill_rect(img, rect3, 255);
+
+ array2d<unsigned char> labels;
+ unsigned long num;
+ num = label_connected_blobs(img,
+ zero_pixels_are_background(),
+ neighbors_8(),
+ connected_if_both_not_zero(),
+ labels);
+
+ DLIB_TEST(num == 4);
+ DLIB_TEST(labels.nr() == img.nr());
+ DLIB_TEST(labels.nc() == img.nc());
+
+ const unsigned char l1 = labels[rect1.top()][rect1.left()];
+ const unsigned char l2 = labels[rect2.top()][rect2.left()];
+ const unsigned char l3 = labels[rect3.top()][rect3.left()];
+
+ DLIB_TEST(l1 != 0 && l2 != 0 && l3 != 0);
+ DLIB_TEST(l1 != l2 && l1 != l3 && l2 != l3);
+
+ for (long r = 0; r < labels.nr(); ++r)
+ {
+ for (long c = 0; c < labels.nc(); ++c)
+ {
+ if (rect1.contains(c,r))
+ {
+ DLIB_TEST(labels[r][c] == l1);
+ }
+ else if (rect2.contains(c,r))
+ {
+ DLIB_TEST(labels[r][c] == l2);
+ }
+ else if (rect3.contains(c,r))
+ {
+ DLIB_TEST(labels[r][c] == l3);
+ }
+ else
+ {
+ DLIB_TEST(labels[r][c] == 0);
+ }
+ }
+ }
+ }
+
+ void test_label_connected_blobs2()
+ {
+ array2d<unsigned char> img;
+ img.set_size(400,401);
+
+ assign_all_pixels(img,0);
+
+ rectangle rect1, rect2, rect3;
+
+ rect1 = centered_rect(99,120, 50,70);
+ rect2 = centered_rect(199,80, 34,68);
+ rect3 = centered_rect(249,180, 120,78);
+
+ fill_rect(img, rect1, 255);
+ fill_rect(img, rect2, 253);
+ fill_rect(img, rect3, 255);
+
+ array2d<unsigned char> labels;
+ unsigned long num;
+ num = label_connected_blobs(img,
+ nothing_is_background(),
+ neighbors_4(),
+ connected_if_equal(),
+ labels);
+
+ DLIB_TEST(num == 5);
+ DLIB_TEST(labels.nr() == img.nr());
+ DLIB_TEST(labels.nc() == img.nc());
+
+ const unsigned char l0 = labels[0][0];
+ const unsigned char l1 = labels[rect1.top()][rect1.left()];
+ const unsigned char l2 = labels[rect2.top()][rect2.left()];
+ const unsigned char l3 = labels[rect3.top()][rect3.left()];
+
+ DLIB_TEST(l0 != 0 && l1 != 0 && l2 != 0 && l3 != 0);
+ DLIB_TEST(l1 != l2 && l1 != l3 && l2 != l3 &&
+ l0 != l1 && l0 != l2 && l0 != l3);
+
+ for (long r = 0; r < labels.nr(); ++r)
+ {
+ for (long c = 0; c < labels.nc(); ++c)
+ {
+ if (rect1.contains(c,r))
+ {
+ DLIB_TEST(labels[r][c] == l1);
+ }
+ else if (rect2.contains(c,r))
+ {
+ DLIB_TEST(labels[r][c] == l2);
+ }
+ else if (rect3.contains(c,r))
+ {
+ DLIB_TEST(labels[r][c] == l3);
+ }
+ else
+ {
+ DLIB_TEST(labels[r][c] == l0);
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename in_image_type,
+ typename out_image_type
+ >
+ void downsample_image (
+ const unsigned long downsample,
+ const in_image_type& in_img,
+ out_image_type& out_img,
+ bool add_to
+ )
+ {
+ out_img.set_size((in_img.nr()+downsample-1)/downsample,
+ (in_img.nc()+downsample-1)/downsample);
+
+ for (long r = 0; r < out_img.nr(); ++r)
+ {
+ for (long c = 0; c < out_img.nc(); ++c)
+ {
+ if (add_to)
+ out_img[r][c] += in_img[r*downsample][c*downsample];
+ else
+ out_img[r][c] = in_img[r*downsample][c*downsample];
+ }
+ }
+ }
+
+ template <
+ typename in_image_type,
+ typename out_image_type,
+ typename EXP1,
+ typename EXP2,
+ typename T
+ >
+ void test_spatially_filter_image_separable_down_simple (
+ const unsigned long downsample,
+ const in_image_type& in_img,
+ out_image_type& out_img,
+ const matrix_exp<EXP1>& row_filter,
+ const matrix_exp<EXP2>& col_filter,
+ T scale,
+ bool use_abs = false,
+ bool add_to = false
+ )
+ {
+ out_image_type temp;
+ spatially_filter_image_separable(in_img, temp, row_filter, col_filter, scale, use_abs, false);
+ downsample_image(downsample, temp, out_img, add_to);
+ }
+
+
+
+
+ template <unsigned long downsample>
+ void test_downsampled_filtering_helper(long row_filt_size, long col_filt_size)
+ {
+ print_spinner();
+ dlog << LTRACE << "***********************************";
+ dlog << LTRACE << "downsample: " << downsample;
+ dlog << LTRACE << "row_filt_size: "<< row_filt_size;
+ dlog << LTRACE << "col_filt_size: "<< col_filt_size;
+ dlib::rand rnd;
+ array2d<int> out1, out2;
+ for (long nr = 0; nr < 3; ++nr)
+ {
+ for (long nc = 0; nc < 3; ++nc)
+ {
+ dlog << LTRACE << "nr: "<< nr;
+ dlog << LTRACE << "nc: "<< nc;
+ array2d<unsigned char> img(25+nr,25+nc);
+ for (int k = 0; k < 5; ++k)
+ {
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ img[r][c] = rnd.get_random_8bit_number();
+ }
+ }
+
+ matrix<int,0,1> row_filter(row_filt_size);
+ matrix<int,0,1> col_filter(col_filt_size);
+
+ row_filter = matrix_cast<int>(10*randm(row_filt_size,1, rnd));
+ col_filter = matrix_cast<int>(10*randm(col_filt_size,1, rnd));
+
+ row_filter -= 3;
+ col_filter -= 3;
+
+
+ test_spatially_filter_image_separable_down_simple(downsample, img, out1, row_filter, col_filter,1 );
+ spatially_filter_image_separable_down(downsample, img, out2, row_filter, col_filter);
+
+ DLIB_TEST(get_rect(out1) == get_rect(out2));
+ DLIB_TEST(mat(out1) == mat(out2));
+
+ test_spatially_filter_image_separable_down_simple(downsample, img, out1, row_filter, col_filter,3, true, true );
+ spatially_filter_image_separable_down(downsample, img, out2, row_filter, col_filter, 3, true, true);
+
+ DLIB_TEST(get_rect(out1) == get_rect(out2));
+ DLIB_TEST(mat(out1) == mat(out2));
+
+ }
+ }
+ }
+ }
+
+ void test_downsampled_filtering()
+ {
+ test_downsampled_filtering_helper<1>(5,5);
+ test_downsampled_filtering_helper<2>(5,5);
+ test_downsampled_filtering_helper<3>(5,5);
+ test_downsampled_filtering_helper<1>(3,5);
+ test_downsampled_filtering_helper<2>(3,5);
+ test_downsampled_filtering_helper<3>(3,5);
+ test_downsampled_filtering_helper<1>(5,3);
+ test_downsampled_filtering_helper<2>(5,3);
+ test_downsampled_filtering_helper<3>(5,3);
+
+ test_downsampled_filtering_helper<1>(3,3);
+ test_downsampled_filtering_helper<2>(3,3);
+ test_downsampled_filtering_helper<3>(3,3);
+
+ test_downsampled_filtering_helper<1>(1,1);
+ test_downsampled_filtering_helper<2>(1,1);
+ test_downsampled_filtering_helper<3>(1,1);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ void test_segment_image()
+ {
+ print_spinner();
+ array2d<T> img(100,100);
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ if (c < 50 || r < 50)
+ assign_pixel(img[r][c], 0);
+ else
+ assign_pixel(img[r][c], 255);
+ }
+ }
+
+ array2d<unsigned long> out;
+ segment_image(img, out);
+
+ DLIB_TEST(get_rect(img) == get_rect(out));
+ const unsigned long v1 = out[0][0];
+ const unsigned long v2 = out[90][90];
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ if (c < 50 || r < 50)
+ {
+ DLIB_TEST(out[r][c] == v1);
+ }
+ else
+ {
+ DLIB_TEST(out[r][c] == v2);
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ void test_dng_floats(double scale)
+ {
+ dlog << LINFO << "in test_dng_floats";
+ print_spinner();
+ array2d<T> img(100,101);
+
+ dlib::rand rnd;
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ T val = rnd.get_random_double()*scale;
+ img[r][c] = val;
+
+ // Lets the float_details object while we are here doing this stuff.
+ float_details temp = val;
+ T val2 = temp;
+ // for the same type we should exactly reproduce the value (unless
+ // it's long double and then maybe it's slightly different).
+ if (is_same_type<T,long double>::value)
+ {
+ DLIB_TEST(std::abs(val2-val) < scale*std::numeric_limits<T>::epsilon());
+ }
+ else
+ {
+ DLIB_TEST(val2 == val);
+ }
+
+ float valf = temp;
+ double vald = temp;
+ long double vall = temp;
+
+ DLIB_TEST(std::abs(valf-val) < scale*std::numeric_limits<float>::epsilon());
+ DLIB_TEST(std::abs(vald-val) < scale*std::numeric_limits<double>::epsilon());
+ DLIB_TEST(std::abs(vall-val) < scale*std::numeric_limits<long double>::epsilon());
+ }
+ }
+
+ ostringstream sout;
+ save_dng(img, sout);
+ istringstream sin;
+
+ array2d<float> img1;
+ array2d<double> img2;
+ array2d<long double> img3;
+
+ sin.clear(); sin.str(sout.str());
+ load_dng(img1, sin);
+
+ sin.clear(); sin.str(sout.str());
+ load_dng(img2, sin);
+
+ sin.clear(); sin.str(sout.str());
+ load_dng(img3, sin);
+
+ DLIB_TEST(img.nr() == img1.nr());
+ DLIB_TEST(img.nr() == img2.nr());
+ DLIB_TEST(img.nr() == img3.nr());
+ DLIB_TEST(img.nc() == img1.nc());
+ DLIB_TEST(img.nc() == img2.nc());
+ DLIB_TEST(img.nc() == img3.nc());
+
+ DLIB_TEST(max(abs(mat(img) - matrix_cast<T>(mat(img1)))) < scale*std::numeric_limits<float>::epsilon());
+ DLIB_TEST(max(abs(mat(img) - matrix_cast<T>(mat(img2)))) < scale*std::numeric_limits<double>::epsilon());
+ DLIB_TEST(max(abs(mat(img) - matrix_cast<T>(mat(img3)))) < scale*std::numeric_limits<long double>::epsilon());
+ }
+
+ void test_dng_float_int()
+ {
+ dlog << LINFO << "in test_dng_float_int";
+ print_spinner();
+
+ array2d<uint16> img;
+ assign_image(img, gaussian_randm(101,100)*10000);
+
+ ostringstream sout;
+ save_dng(img, sout);
+ istringstream sin(sout.str());
+ array2d<double> img2;
+ load_dng(img2, sin);
+ sout.clear(); sout.str("");
+
+ save_dng(img2, sout);
+ sin.clear(); sin.str(sout.str());
+ array2d<uint16> img3;
+ load_dng(img3, sin);
+
+ // this whole thing should have been totally lossless.
+ DLIB_TEST(mat(img) == mat(img3));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ void test_filtering_center (
+ dlib::rand& rnd
+ )
+ {
+ array2d<T> img(rnd.get_random_32bit_number()%100+1,
+ rnd.get_random_32bit_number()%100+1);
+ matrix<T> filt(rnd.get_random_32bit_number()%10+1,
+ rnd.get_random_32bit_number()%10+1);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ img[r][c] = rnd.get_random_32bit_number()%100;
+ }
+ }
+ for (long r = 0; r < filt.nr(); ++r)
+ {
+ for (long c = 0; c < filt.nc(); ++c)
+ {
+ filt(r,c) = rnd.get_random_32bit_number()%100;
+ }
+ }
+
+ array2d<T> out;
+ const rectangle area = spatially_filter_image(img, out, filt);
+
+ for (long r = 0; r < out.nr(); ++r)
+ {
+ for (long c = 0; c < out.nc(); ++c)
+ {
+ const rectangle rect = centered_rect(point(c,r), filt.nc(), filt.nr());
+ if (get_rect(out).contains(rect))
+ {
+ T val = sum(pointwise_multiply(filt, subm(mat(img),rect)));
+ DLIB_TEST_MSG(val == out[r][c],"err: " << val-out[r][c]);
+ DLIB_TEST(area.contains(point(c,r)));
+ }
+ else
+ {
+ DLIB_TEST(!area.contains(point(c,r)));
+ }
+ }
+ }
+ }
+
+ template <typename T>
+ void test_separable_filtering_center (
+ dlib::rand& rnd
+ )
+ {
+ array2d<T> img(rnd.get_random_32bit_number()%100+1,
+ rnd.get_random_32bit_number()%100+1);
+ matrix<T,1,0> row_filt(rnd.get_random_32bit_number()%10+1);
+ matrix<T,0,1> col_filt(rnd.get_random_32bit_number()%10+1);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ img[r][c] = rnd.get_random_32bit_number()%10;
+ }
+ }
+ for (long r = 0; r < row_filt.size(); ++r)
+ {
+ row_filt(r) = rnd.get_random_32bit_number()%10;
+ }
+ for (long r = 0; r < col_filt.size(); ++r)
+ {
+ col_filt(r) = rnd.get_random_32bit_number()%10;
+ }
+
+ array2d<T> out;
+ const rectangle area = spatially_filter_image_separable(img, out, row_filt, col_filt);
+
+ for (long r = 0; r < out.nr(); ++r)
+ {
+ for (long c = 0; c < out.nc(); ++c)
+ {
+ const rectangle rect = centered_rect(point(c,r), row_filt.size(), col_filt.size());
+ if (get_rect(out).contains(rect))
+ {
+ T val = sum(pointwise_multiply(col_filt*row_filt, subm(mat(img),rect)));
+ DLIB_TEST_MSG(val == out[r][c],"err: " << val-out[r][c]);
+
+ DLIB_TEST(area.contains(point(c,r)));
+ }
+ else
+ {
+ DLIB_TEST(!area.contains(point(c,r)));
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_hough_test()
+ {
+ array2d<unsigned char> img(300,300);
+
+
+ for (int k = -2; k <= 2; ++k)
+ {
+ print_spinner();
+ running_stats<double> rs;
+ array2d<int> himg;
+ hough_transform ht(200+k);
+ double angle1 = 0;
+ double angle2 = 0;
+ const int len = 90;
+ // Draw a bunch of random lines, hough transform them, then make sure the hough
+ // transform detects them accurately.
+ for (int i = 0; i < 500; ++i)
+ {
+ point cent = center(get_rect(img));
+ point arc = cent + point(len,0);
+ arc = rotate_point(cent, arc, angle1);
+
+ point l = arc + point(500,0);
+ point r = arc - point(500,0);
+ l = rotate_point(arc, l, angle2);
+ r = rotate_point(arc, r, angle2);
+
+ angle1 += pi/13;
+ angle2 += pi/40;
+
+ assign_all_pixels(img, 0);
+ draw_line(img, l, r, 255);
+ rectangle box = translate_rect(get_rect(ht),point(50,50));
+ ht(img, box, himg);
+
+ point p = max_point(mat(himg));
+ DLIB_TEST(himg[p.y()][p.x()] > 255*3);
+
+ l -= point(50,50);
+ r -= point(50,50);
+ std::pair<point,point> line = ht.get_line(p);
+ // make sure the best scoring hough point matches the line we drew.
+ double dist1 = distance_to_line(make_pair(l,r), line.first);
+ double dist2 = distance_to_line(make_pair(l,r), line.second);
+ //cout << "DIST1: " << dist1 << endl;
+ //cout << "DIST2: " << dist2 << endl;
+ rs.add(dist1);
+ rs.add(dist2);
+ DLIB_TEST(dist1 < 2.5);
+ DLIB_TEST(dist2 < 2.5);
+ }
+ //cout << "rs.mean(): " << rs.mean() << endl;
+ DLIB_TEST(rs.mean() < 0.7);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_extract_image_chips()
+ {
+ dlib::rand rnd;
+
+ // Make sure that cropping a white box out of a larger white image always produces an
+ // exact white box. This should catch any bad border effects from a messed up internal
+ // cropping.
+ for (int iter = 0; iter < 1000; ++iter)
+ {
+ print_spinner();
+ const long nr = rnd.get_random_32bit_number()%100 + 1;
+ const long nc = rnd.get_random_32bit_number()%100 + 1;
+ const long size = rnd.get_random_32bit_number()%10000 + 4;
+ const double angle = rnd.get_random_double() * pi;
+
+ matrix<int> img(501,501), chip;
+ img = 255;
+ chip_details details(centered_rect(center(get_rect(img)),nr,nc), size, angle);
+ extract_image_chip(img, details, chip);
+ DLIB_TEST_MSG(max(abs(chip-255))==0,"nr: " << nr << " nc: "<< nc << " size: " << size << " angle: " << angle
+ << " error: " << max(abs(chip-255)) );
+ }
+
+
+ {
+ // Make sure that the interpolation in extract_image_chip() keeps stuff in the
+ // right places.
+
+ matrix<unsigned char> img(10,10), chip;
+ img = 0;
+ img(1,1) = 255;
+ img(8,8) = 255;
+
+ extract_image_chip(img, chip_details(get_rect(img), 9*9), chip);
+
+ DLIB_TEST(chip(1,1) == 195);
+ DLIB_TEST(chip(7,7) == 195);
+ chip(1,1) -= 195;
+ chip(7,7) -= 195;
+ DLIB_TEST(sum(matrix_cast<int>(chip)) == 0);
+ }
+
+
+
+ // Test the rotation ability of extract_image_chip(). Do this by drawing a line and
+ // then rotating it so it's horizontal. Check that it worked correctly by hough
+ // transforming it.
+ hough_transform ht(151);
+ matrix<unsigned char> img(300,300);
+ for (int iter = 0; iter < 1000; ++iter)
+ {
+ print_spinner();
+ img = 0;
+ const int len = 9000;
+ point cent = center(get_rect(img));
+ point l = cent + point(len,0);
+ point r = cent - point(len,0);
+ const double angle = rnd.get_random_double()*pi*3;
+ l = rotate_point(cent, l, angle);
+ r = rotate_point(cent, r, angle);
+ draw_line(img, l, r, 255);
+
+
+ const long wsize = rnd.get_random_32bit_number()%350 + 150;
+
+ matrix<unsigned char> temp;
+ chip_details details(centered_rect(center(get_rect(img)), wsize,wsize), chip_dims(ht.size(),ht.size()), angle);
+ extract_image_chip(img, details, temp);
+
+
+ matrix<long> tform;
+ ht(temp, get_rect(temp), tform);
+ std::pair<point,point> line = ht.get_line(max_point(tform));
+
+ DLIB_TEST_MSG(line.first.y() == line.second.y()," wsize: " << wsize);
+ DLIB_TEST(length(line.first-line.second) > 100);
+ DLIB_TEST(length((line.first+line.second)/2.0 - center(get_rect(temp))) <= 1);
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class image_tester : public tester
+ {
+ public:
+ image_tester (
+ ) :
+ tester ("test_image",
+ "Runs tests on the image processing objects and functions.")
+ {}
+
+ void perform_test (
+ )
+ {
+ image_test();
+ run_hough_test();
+ test_extract_image_chips();
+ test_integral_image<long, unsigned char>();
+ test_integral_image<double, int>();
+ test_integral_image<long, unsigned char>();
+ test_integral_image<double, float>();
+
+ test_zero_border_pixels();
+
+ test_filtering<unsigned char>(false,1);
+ test_filtering<unsigned char>(true,1);
+ test_filtering<unsigned char>(false,3);
+ test_filtering<unsigned char>(true,3);
+ test_filtering<int>(false,1);
+ test_filtering<int>(true,1);
+ test_filtering<int>(false,3);
+ test_filtering<int>(true,3);
+
+ test_label_connected_blobs();
+ test_label_connected_blobs2();
+ test_downsampled_filtering();
+
+ test_segment_image<unsigned char>();
+ test_segment_image<unsigned short>();
+ test_segment_image<double>();
+ test_segment_image<int>();
+ test_segment_image<rgb_pixel>();
+ test_segment_image<rgb_alpha_pixel>();
+
+ test_dng_floats<float>(1);
+ test_dng_floats<double>(1);
+ test_dng_floats<long double>(1);
+ test_dng_floats<float>(1e30);
+ test_dng_floats<double>(1e30);
+ test_dng_floats<long double>(1e30);
+
+ test_dng_float_int();
+
+ dlib::rand rnd;
+ for (int i = 0; i < 10; ++i)
+ {
+ // the spatial filtering stuff is the same as xcorr_same when the filter
+ // sizes are odd.
+ test_filtering2(3,3,rnd);
+ test_filtering2(5,5,rnd);
+ test_filtering2(7,7,rnd);
+ }
+
+ for (int i = 0; i < 100; ++i)
+ test_filtering_center<float>(rnd);
+ for (int i = 0; i < 100; ++i)
+ test_filtering_center<int>(rnd);
+ for (int i = 0; i < 100; ++i)
+ test_separable_filtering_center<int>(rnd);
+ for (int i = 0; i < 100; ++i)
+ test_separable_filtering_center<float>(rnd);
+
+ {
+ print_spinner();
+ matrix<unsigned char> img(40,80);
+ assign_all_pixels(img, 255);
+ skeleton(img);
+
+ DLIB_TEST(sum(matrix_cast<int>(mat(img)))/255 == 40);
+ draw_line(img, point(20,19), point(59,19), 00);
+ DLIB_TEST(sum(matrix_cast<int>(mat(img))) == 0);
+ }
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/iosockstream.cpp b/ml/dlib/dlib/test/iosockstream.cpp
new file mode 100644
index 000000000..c68de7bd3
--- /dev/null
+++ b/ml/dlib/dlib/test/iosockstream.cpp
@@ -0,0 +1,181 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/iosockstream.h>
+#include <dlib/server.h>
+#include <vector>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+
+ logger dlog("test.iosockstream");
+
+// ----------------------------------------------------------------------------------------
+
+ class serv : public server_iostream
+ {
+ virtual void on_connect (
+ std::istream& in,
+ std::ostream& out,
+ const std::string& ,
+ const std::string& ,
+ unsigned short ,
+ unsigned short ,
+ uint64
+ )
+ {
+ try
+ {
+ dlog << LINFO << "serv1: serving connection";
+
+ std::string temp;
+ in >> temp;
+ DLIB_TEST(temp == "word");
+ in >> temp;
+ DLIB_TEST(temp == "another");
+ out << "yay words ";
+ in >> temp;
+ DLIB_TEST(temp == "yep");
+ }
+ catch (error& e)
+ {
+ error_string = e.what();
+ }
+
+ }
+
+
+ public:
+ std::string error_string;
+
+ };
+
+ class serv2 : public server_iostream
+ {
+ virtual void on_connect (
+ std::istream& ,
+ std::ostream& out,
+ const std::string& ,
+ const std::string& ,
+ unsigned short ,
+ unsigned short ,
+ uint64
+ )
+ {
+ try
+ {
+ dlog << LINFO << "serv2: serving connection";
+
+ out << "one two three four five";
+ }
+ catch (error& e)
+ {
+ error_string = e.what();
+ }
+
+ }
+
+
+ public:
+ std::string error_string;
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ void test1()
+ {
+ dlog << LINFO << "in test1()";
+ serv theserv;
+ theserv.set_listening_port(12345);
+ theserv.start_async();
+
+ // wait a little bit to make sure the server has started listening before we try
+ // to connect to it.
+ dlib::sleep(500);
+
+ for (int i = 0; i < 200; ++i)
+ {
+ dlog << LINFO << "i: " << i;
+ print_spinner();
+ iosockstream stream("localhost:12345");
+
+ stream << "word another ";
+ std::string temp;
+ stream >> temp;
+ DLIB_TEST(temp == "yay");
+ stream >> temp;
+ DLIB_TEST(temp == "words");
+ stream << "yep ";
+ }
+
+ // Just to make sure the server finishes processing the last connection before
+ // we kill it and accidentally trigger a DLIB_TEST().
+ dlib::sleep(500);
+
+ if (theserv.error_string.size() != 0)
+ throw error(theserv.error_string);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test2()
+ {
+ dlog << LINFO << "in test2()";
+ serv2 theserv;
+ theserv.set_listening_port(12345);
+ theserv.start_async();
+
+ // wait a little bit to make sure the server has started listening before we try
+ // to connect to it.
+ dlib::sleep(500);
+
+ for (int i = 0; i < 200; ++i)
+ {
+ dlog << LINFO << "i: " << i;
+ print_spinner();
+ iosockstream stream("localhost:12345");
+
+ std::string temp;
+ stream >> temp; DLIB_TEST(temp == "one");
+ stream >> temp; DLIB_TEST(temp == "two");
+ stream >> temp; DLIB_TEST(temp == "three");
+ stream >> temp; DLIB_TEST(temp == "four");
+ stream >> temp; DLIB_TEST(temp == "five");
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_iosockstream : public tester
+ {
+ public:
+ test_iosockstream (
+ ) :
+ tester ("test_iosockstream",
+ "Runs tests on the iosockstream component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test1();
+ test2();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/is_same_object.cpp b/ml/dlib/dlib/test/is_same_object.cpp
new file mode 100644
index 000000000..ed71c5bef
--- /dev/null
+++ b/ml/dlib/dlib/test/is_same_object.cpp
@@ -0,0 +1,141 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm.h>
+#include <vector>
+#include <sstream>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.is_same_object");
+
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_booya_template, void, template booya<int>, (std::string)const);
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_booya2_template, void, template booya2<int>, (int)const);
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_funct_int, void, funct, (int));
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_funct_double, void, funct, (double));
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_funct_f, float, funct_f, (int));
+
+ class htest
+ {
+ public:
+ template <typename EXP>
+ void booya(std::string) const {}
+
+ template <typename EXP>
+ void booya2(EXP) const {}
+
+ void funct(double) {}
+ };
+
+ class htest2
+ {
+ public:
+
+ void funct(int) {}
+
+ float funct_f(int) { return 0;}
+ };
+
+ void test_metaprog()
+ {
+ DLIB_TEST(has_booya2_template<htest>::value == true);
+ DLIB_TEST(has_booya2_template<htest2>::value == false);
+
+#if _MSC_VER > 1600 // there is a bug in visual studio 2010 and older that prevents this test from working
+ DLIB_TEST(has_booya_template<htest>::value == true);
+#endif
+
+ DLIB_TEST(has_booya_template<htest2>::value == false);
+
+ DLIB_TEST(has_funct_int<htest>::value == false);
+ DLIB_TEST(has_funct_int<htest2>::value == true);
+ DLIB_TEST(has_funct_double<htest>::value == true);
+ DLIB_TEST(has_funct_double<htest2>::value == false);
+
+ DLIB_TEST(has_funct_f<htest>::value == false);
+ DLIB_TEST(has_funct_f<htest2>::value == true);
+ }
+
+ class is_same_object_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ is_same_object_tester (
+ ) :
+ tester (
+ "test_is_same_object", // the command line argument name for this test
+ "Run tests on the is_same_object function.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+ struct base {};
+ struct derived : public base {};
+
+ template <bool truth>
+ void go(const base& a, const base& b)
+ {
+ DLIB_TEST( is_same_object(a,b) == truth) ;
+ DLIB_TEST( is_same_object(b,a) == truth) ;
+ }
+
+
+ template <bool truth>
+ void go2(const base& a, const derived& b)
+ {
+ DLIB_TEST( is_same_object(a,b) == truth) ;
+ DLIB_TEST( is_same_object(b,a) == truth) ;
+ }
+
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+
+ int a, b;
+ double d;
+ DLIB_TEST( is_same_object(a,a) == true) ;
+ DLIB_TEST( is_same_object(a,b) == false) ;
+ DLIB_TEST( is_same_object(d,b) == false) ;
+ DLIB_TEST( is_same_object(d,d) == true) ;
+
+ base sb;
+ derived sd, sd2;
+
+ DLIB_TEST( is_same_object(sb,sd) == false) ;
+ DLIB_TEST( is_same_object(sd,sb) == false) ;
+
+ go<true>(sd, sd);
+ go<false>(sd, sd2);
+ go<true>(sb, sb);
+ go<false>(sd, sb);
+
+ go2<true>(sd, sd);
+ go2<false>(sd2, sd);
+ go2<false>(sd, sd2);
+ go2<false>(sb, sd);
+
+ test_metaprog();
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ is_same_object_tester a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/isotonic_regression.cpp b/ml/dlib/dlib/test/isotonic_regression.cpp
new file mode 100644
index 000000000..2ab46903c
--- /dev/null
+++ b/ml/dlib/dlib/test/isotonic_regression.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2018 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/optimization.h>
+#include <dlib/global_optimization.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.isotonic_regression");
+
+// ----------------------------------------------------------------------------------------
+
+ class optimization_tester : public tester
+ {
+ public:
+ optimization_tester (
+ ) :
+ tester ("test_isotonic_regression",
+ "Runs tests on the isotonic_regression object.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlib::rand rnd;
+
+ for (int round = 0; round < 100; ++round)
+ {
+ print_spinner();
+ std::vector<double> vect;
+ for (int i = 0; i < 5; ++i)
+ vect.push_back(put_in_range(-1,1,rnd.get_random_gaussian()));
+
+
+ auto f = [&](const matrix<double,0,1>& x)
+ {
+ double dist = 0;
+ double sum = 0;
+ for (long i = 0; i < x.size(); ++i)
+ {
+ sum += x(i);
+ dist += (sum-vect[i])*(sum-vect[i]);
+ }
+ return dist;
+ };
+
+ auto objval = [vect](const matrix<double,0,1>& x)
+ {
+ return sum(squared(mat(vect)-x));
+ };
+
+ auto is_monotonic = [](const matrix<double,0,1>& x)
+ {
+ for (long i = 1; i < x.size(); ++i)
+ {
+ if (x(i-1) > x(i))
+ return false;
+ }
+ return true;
+ };
+
+ matrix<double,0,1> lower(5), upper(5);
+ lower = 0;
+ lower(0) = -4;
+ upper = 4;
+ // find the solution with find_min_global() and then check that it matches
+ auto result = find_min_global(f, lower, upper, max_function_calls(40));
+
+ for (long i = 1; i < result.x.size(); ++i)
+ result.x(i) += result.x(i-1);
+
+ isotonic_regression mr;
+ mr(vect);
+
+ dlog << LINFO << "err: "<< objval(mat(vect)) - objval(result.x);
+
+ DLIB_CASSERT(is_monotonic(mat(vect)));
+ DLIB_CASSERT(is_monotonic(result.x));
+ // isotonic_regression should be at least as good as find_min_global().
+ DLIB_CASSERT(objval(mat(vect)) - objval(result.x) < 1e-13);
+ }
+
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/kcentroid.cpp b/ml/dlib/dlib/test/kcentroid.cpp
new file mode 100644
index 000000000..c16ab6eca
--- /dev/null
+++ b/ml/dlib/dlib/test/kcentroid.cpp
@@ -0,0 +1,684 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include <map>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+#include "checkerboard.h"
+#include <dlib/statistics.h>
+
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.kcentroid");
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ struct unopt_sparse_linear_kernel
+ {
+ typedef typename T::value_type::second_type scalar_type;
+ typedef T sample_type;
+ typedef default_memory_manager mem_manager_type;
+
+ scalar_type operator() (
+ const sample_type& a,
+ const sample_type& b
+ ) const
+ {
+ return dot(a,b);
+ }
+
+ bool operator== (
+ const unopt_sparse_linear_kernel&
+ ) const
+ {
+ return true;
+ }
+ };
+
+ template <typename T>
+ struct unopt_linear_kernel
+ {
+ typedef typename T::type scalar_type;
+ typedef T sample_type;
+ typedef typename T::mem_manager_type mem_manager_type;
+
+ scalar_type operator() (
+ const sample_type& a,
+ const sample_type& b
+ ) const
+ {
+ return trans(a)*b;
+ }
+
+ bool operator== (
+ const unopt_linear_kernel&
+ ) const
+ {
+ return true;
+ }
+ };
+
+ bool approx_equal(double a, double b)
+ {
+ return (std::abs(a-b) < 1000*(std::numeric_limits<double>::epsilon()));
+ }
+
+ bool approx_equal(double a, double b, double eps)
+ {
+ return (std::abs(a-b) < eps);
+ }
+
+ template <typename K>
+ double dist (
+ const K& k,
+ const matrix<double,4,1>& a,
+ const matrix<double,5,1>& b
+ )
+ /*!
+ ensures
+ - returns the distance between the a and b vectors in the
+ feature space defined by the given kernel k.
+ !*/
+ {
+ const double bias = std::sqrt(k.offset);
+ return std::sqrt(length_squared(a-colm(b,0,4)) + std::pow(b(4)-bias,2.0));
+
+ }
+
+ template <typename K>
+ double dist (
+ const K& k,
+ std::map<unsigned long,double> a,
+ std::map<unsigned long,double> b
+ )
+ /*!
+ ensures
+ - returns the distance between the a and b vectors in the
+ feature space defined by the given kernel k.
+ !*/
+ {
+ double temp = 0;
+ const double bias = std::sqrt(k.offset);
+ temp += std::pow(a[0]-b[0],2.0);
+ temp += std::pow(a[1]-b[1],2.0);
+ temp += std::pow(a[2]-b[2],2.0);
+ temp += std::pow(a[3]-b[3],2.0);
+ temp += std::pow(bias-b[4],2.0);
+
+ return std::sqrt(temp);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename kernel_type>
+ void test_kcentroid_with_linear_kernel(
+ )
+ /*!
+ requires
+ - kernel_type::sample_type == a matrix<double,5,1>
+ - kernel_type == a kernel that just computes a dot product
+ between its inputs. I.e. a linear kernel
+ ensures
+ - tests the kcentroid object with the given kernel
+ !*/
+ {
+ // Here we declare that our samples will be 2 dimensional column vectors.
+ typedef typename kernel_type::sample_type sample_type;
+
+ kernel_type default_kernel;
+ kcentroid<kernel_type> test(default_kernel,0.001,20);
+
+ sample_type temp, temp2;
+
+ temp = 2,0,0,0,0;
+ dlog << LDEBUG << test(temp) ;
+ dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ;
+
+ DLIB_TEST(approx_equal(test(temp), 2));
+ DLIB_TEST(approx_equal(test.squared_norm(), 0));
+
+ // make test store the point(2,0,0,0,0)
+ test.train(temp, 0, 1);
+ dlog << LDEBUG << test(temp) ;
+ dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ;
+ DLIB_TEST(approx_equal(test(temp), 0));
+ DLIB_TEST(approx_equal(test.get_distance_function()(temp), 0));
+ DLIB_TEST(approx_equal(test.squared_norm(), 4));
+
+ temp = 0,2,0,0,0;
+ dlog << LDEBUG << test(temp) ;
+ DLIB_TEST(approx_equal(test(temp), std::sqrt(2*2 + 2*2.0)));
+ DLIB_TEST(approx_equal(test.squared_norm(), 4));
+
+ // make test store the point(0,2,0,0,0)
+ test.train(temp, 0, 1);
+
+ dlog << LDEBUG << test(temp) ;
+ DLIB_TEST(approx_equal(test(temp), 0));
+ DLIB_TEST(approx_equal(test.squared_norm(), 4));
+
+ temp = 2,0,0,0,0;
+ DLIB_TEST(approx_equal(test(temp), std::sqrt(2*2 + 2*2.0)));
+ DLIB_TEST(approx_equal(test.squared_norm(), 4));
+
+ // make test store the point(1,1,0,0,0)
+ test.train(temp, 0.5, 0.5);
+
+ temp = 0;
+ DLIB_TEST(approx_equal(test(temp), std::sqrt(2.0)));
+ DLIB_TEST(approx_equal(test.squared_norm(), 2));
+
+ // make test store the point(1,1,0,3,0)
+ temp = 0,0,0,3,0;
+ temp2 = 1,1,0,3,0;
+ test.train(temp, 1, 1);
+
+ temp = 0;
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ temp = 1,2,3,4,5;
+ DLIB_TEST(approx_equal(test(temp), length(temp2-temp)));
+ DLIB_TEST(approx_equal(test.get_distance_function()(temp), length(temp2-temp)));
+
+ // make test store the point(0,1,0,3,-1)
+ temp = 1,0,0,0,1;
+ test.train(temp, 1, -1);
+ temp2 = 0,1,0,3,-1;
+
+ temp = 0;
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ temp = 1,2,3,4,5;
+ DLIB_TEST(approx_equal(test(temp), length(temp2-temp)));
+
+
+ // make test store the -1*point(0,1,0,3,-1)
+ temp = 0,0,0,0,0;
+ test.train(temp, -1, 0);
+ temp2 = -temp2;
+
+ temp = 0;
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ temp = 1,2,-3,4,5;
+ DLIB_TEST(approx_equal(test(temp), length(temp2-temp)));
+
+
+
+ // make test store the point(0,0,0,0,0)
+ temp = 0,0,0,0,0;
+ test.train(temp, 0, 0);
+ temp2 = 0;
+
+ temp = 0;
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ temp = 1,2,-3,4,5;
+ DLIB_TEST(approx_equal(test(temp), length(temp2-temp)));
+
+
+
+ // make test store the point(1,0,0,0,0)
+ temp = 1,0,0,0,0;
+ test.train(temp, 1, 1);
+ temp2 = 1,0,0,0,0;
+
+ temp = 0;
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ DLIB_TEST(approx_equal(test.inner_product(test), length_squared(temp2)));
+ temp = 1,2,-3,4,5;
+ DLIB_TEST(approx_equal(test(temp), length(temp2-temp)));
+ DLIB_TEST(approx_equal(test(test), 0));
+ DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0));
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename kernel_type>
+ void test_kcentroid_with_offset_linear_kernel(
+ )
+ /*!
+ requires
+ - kernel_type::sample_type == a matrix<double,4,1>
+ - kernel_type == a kernel that just computes a dot product
+ between its inputs + some constant. I.e. a linear kernel
+ wrapped by offset_kernel
+ ensures
+ - tests the kcentroid object with the given kernel
+ !*/
+ {
+ // Here we declare that our samples will be 2 dimensional column vectors.
+ typedef typename kernel_type::sample_type sample_type;
+
+ kernel_type k;
+ kcentroid<kernel_type> test(k,0.001,20);
+
+ sample_type temp, temp2, temp3;
+
+ matrix<double,5,1> val, val2;
+
+ const double b = std::sqrt(k.offset);
+
+ temp = 2,0,0,0;
+ temp2 = 0;
+ val = 0;
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+
+
+ temp2 = 0;
+
+ // make test store the point(0,0,0,0,b)
+ val = 0,0,0,0,b;
+ test.train(temp2, 0,1);
+
+ temp = 2,0,0,0;
+ dlog << LDEBUG << test(temp) ;
+ dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ;
+
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val)));
+ DLIB_TEST_MSG(approx_equal(test.get_distance_function()(temp2), dist(k,temp2,val), 1e-6),
+ test.get_distance_function()(temp2) - dist(k,temp2,val) << " compare to: " <<
+ test(temp2) - dist(k,temp2,val)
+ );
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+
+
+ // make test store the point(0,0,0,0,0)
+ val = 0,0,0,0,0;
+ test.train(temp2, 1,-1);
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val)));
+ DLIB_TEST_MSG(approx_equal(test.get_distance_function()(temp2), dist(k,temp2,val)),
+ test.get_distance_function()(temp2) - dist(k,temp2,val) << " compare to: " <<
+ test(temp2) - dist(k,temp2,val)
+ );
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+
+
+
+ val2 = 0,1,0,0,b;
+ val += val2;
+ temp2 = 0,1,0,0;
+ // make test store the point val
+ test.train(temp2, 1,1);
+
+ temp = 1,0,3,0;
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST_MSG(approx_equal(test(temp2), dist(k,temp2,val), 1e-7),
+ test(temp2) - dist(k,temp2,val));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+ DLIB_TEST_MSG(approx_equal(test(test), 0, 1e-7), test(test));
+
+
+ val2 = 0,1,2.6,8,b;
+ val += val2;
+ temp2 = 0,1,2.6,8;
+ // make test store the point val
+ test.train(temp2, 1,1);
+
+ temp = 1,1,3,0;
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST_MSG(approx_equal(test(temp2), dist(k,temp2,val)), test(temp2) - dist(k,temp2,val));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+ DLIB_TEST(approx_equal(test.inner_product(test), length_squared(val)));
+ DLIB_TEST(approx_equal(test(test), 0));
+ DLIB_TEST_MSG(approx_equal(test.get_distance_function()(test.get_distance_function()), 0, 1e-6),
+ test.get_distance_function()(test.get_distance_function()));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename kernel_type>
+ void test_kcentroid_with_sparse_linear_kernel(
+ )
+ /*!
+ requires
+ - kernel_type::sample_type == a std::map<unsigned long,double>
+ - kernel_type == a kernel that just computes a dot product
+ between its inputs. I.e. a linear kernel
+ ensures
+ - tests the kcentroid object with the given kernel
+ !*/
+ {
+ // Here we declare that our samples will be 2 dimensional column vectors.
+ typedef typename kernel_type::sample_type sample_type;
+
+ kernel_type default_kernel;
+ kcentroid<kernel_type> test(default_kernel,0.001,20);
+
+ dlog << LDEBUG << "AAAA 1" ;
+
+ sample_type temp, temp2;
+
+ temp[0] = 2;
+ dlog << LDEBUG << test(temp) ;
+ dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ;
+
+ DLIB_TEST(approx_equal(test(temp), 2));
+ DLIB_TEST(approx_equal(test.squared_norm(), 0));
+
+ // make test store the point(2,0,0,0,0)
+ test.train(temp, 0, 1);
+ dlog << LDEBUG << test(temp) ;
+ dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ;
+ DLIB_TEST(approx_equal(test(temp), 0));
+ DLIB_TEST(approx_equal(test.squared_norm(), 4));
+
+ dlog << LDEBUG << "AAAA 2" ;
+ temp.clear();
+ temp[1] = 2;
+ dlog << LDEBUG << test(temp) ;
+ DLIB_TEST(approx_equal(test(temp), std::sqrt(2*2 + 2*2.0)));
+ DLIB_TEST(approx_equal(test.squared_norm(), 4));
+
+ // make test store the point(0,2,0,0,0)
+ test.train(temp, 0, 1);
+
+ dlog << LDEBUG << test(temp) ;
+ DLIB_TEST(approx_equal(test(temp), 0));
+ DLIB_TEST(approx_equal(test.squared_norm(), 4));
+
+ temp.clear();
+ temp[0] = 2;
+ DLIB_TEST(approx_equal(test(temp), std::sqrt(2*2 + 2*2.0)));
+ DLIB_TEST(approx_equal(test.squared_norm(), 4));
+
+ // make test store the point(1,1,0,0,0)
+ test.train(temp, 0.5, 0.5);
+
+ dlog << LDEBUG << "AAAA 3" ;
+ temp.clear();
+ DLIB_TEST(approx_equal(test(temp), std::sqrt(2.0)));
+ DLIB_TEST(approx_equal(test.squared_norm(), 2));
+ DLIB_TEST(approx_equal(test(test), 0));
+ DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0));
+
+ dlog << LDEBUG << "AAAA 3.1" ;
+ // make test store the point(1,1,0,3,0)
+ temp.clear(); temp[3] = 3;
+ temp2.clear();
+ temp2[0] = 1;
+ temp2[1] = 1;
+ temp2[3] = 3;
+ test.train(temp, 1, 1);
+
+ dlog << LDEBUG << "AAAA 3.2" ;
+ temp.clear();
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ dlog << LDEBUG << "AAAA 3.3" ;
+ temp[0] = 1;
+ temp[1] = 2;
+ temp[2] = 3;
+ temp[3] = 4;
+ temp[4] = 5;
+ dlog << LDEBUG << "AAAA 3.4" ;
+ double junk = dlib::distance(temp2,temp);
+ dlog << LDEBUG << "AAAA 3.5" ;
+ DLIB_TEST(approx_equal(test(temp), junk) );
+
+ dlog << LDEBUG << "AAAA 4" ;
+ // make test store the point(0,1,0,3,-1)
+ temp.clear();
+ temp[0] = 1;
+ temp[4] = 1;
+ test.train(temp, 1, -1);
+ temp2.clear();
+ temp2[1] = 1;
+ temp2[3] = 3;
+ temp2[4] = -1;
+
+ temp.clear();
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ temp[0] = 1;
+ temp[1] = 2;
+ temp[2] = 3;
+ temp[3] = 4;
+ temp[4] = 5;
+ DLIB_TEST(approx_equal(test(temp), dlib::distance(temp2,temp)));
+
+
+ // make test store the -1*point(0,1,0,3,-1)
+ temp.clear();
+ test.train(temp, -1, 0);
+ temp2[0] = -temp2[0];
+ temp2[1] = -temp2[1];
+ temp2[2] = -temp2[2];
+ temp2[3] = -temp2[3];
+ temp2[4] = -temp2[4];
+
+ dlog << LDEBUG << "AAAA 5" ;
+ temp.clear();
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ temp[0] = 1;
+ temp[1] = 2;
+ temp[2] = -3;
+ temp[3] = 4;
+ temp[4] = 5;
+ DLIB_TEST(approx_equal(test(temp), dlib::distance(temp2,temp)));
+
+
+
+ // make test store the point(0,0,0,0,0)
+ temp.clear();
+ test.train(temp, 0, 0);
+ temp2.clear();
+
+ temp.clear();
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ temp[0] = 1;
+ temp[1] = 2;
+ temp[2] = -3;
+ temp[3] = 4;
+ temp[4] = 5;
+ DLIB_TEST(approx_equal(test(temp), dlib::distance(temp2,temp)));
+ DLIB_TEST(approx_equal(test.get_distance_function()(temp), dlib::distance(temp2,temp)));
+
+
+ dlog << LDEBUG << "AAAA 6" ;
+
+ // make test store the point(1,0,0,0,0)
+ temp.clear();
+ temp[0] = 1;
+ test.train(temp, 1, 1);
+ temp2.clear();
+ temp2[0] = 1;
+
+ temp.clear();
+ DLIB_TEST(approx_equal(test(temp), length(temp2)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2)));
+ DLIB_TEST(approx_equal(test.inner_product(test), length_squared(temp2)));
+ temp[0] = 1;
+ temp[1] = 2;
+ temp[2] = -3;
+ temp[3] = 4;
+ temp[4] = 5;
+ DLIB_TEST(approx_equal(test(temp), dlib::distance(temp2,temp)));
+ DLIB_TEST(approx_equal(test.get_distance_function()(temp), dlib::distance(temp2,temp)));
+ DLIB_TEST(approx_equal(test(test), 0));
+ DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0));
+
+ dlog << LDEBUG << "AAAA 7" ;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename kernel_type>
+ void test_kcentroid_with_offset_sparse_linear_kernel(
+ )
+ /*!
+ requires
+ - kernel_type::sample_type == a std::map<unsigned long,double>
+ - kernel_type == a kernel that just computes a dot product
+ between its inputs + some constant. I.e. a linear kernel
+ wrapped by offset_kernel
+ ensures
+ - tests the kcentroid object with the given kernel
+ !*/
+ {
+ // Here we declare that our samples will be 2 dimensional column vectors.
+ typedef typename kernel_type::sample_type sample_type;
+
+ kernel_type k;
+ kcentroid<kernel_type> test(k,0.001,20);
+
+ sample_type temp, temp2, temp3;
+
+ std::map<unsigned long,double> val, val2;
+
+ const double b = std::sqrt(k.offset);
+
+ temp.clear();
+ temp[0] = 2;
+ temp2.clear();
+ val.clear();
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+
+
+ temp2.clear();
+
+ // make test store the point(0,0,0,0,b)
+ val.clear();
+ val[4] = b;
+ test.train(temp2, 0,1);
+
+ temp.clear();
+ temp[0] = 2;
+ dlog << LDEBUG << test(temp) ;
+ dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ;
+
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val)));
+ DLIB_TEST_MSG(approx_equal(test.get_distance_function()(temp2), dist(k,temp2,val), 1e-7),
+ test.get_distance_function()(temp2) - dist(k,temp2,val)
+ );
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+ DLIB_TEST(approx_equal(test(test), 0));
+ DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0, 1e-6));
+
+ // make test store the point(0,0,0,0,0)
+ val.clear();
+ test.train(temp2, 1,-1);
+
+ temp.clear();
+ temp[0] = 2;
+ dlog << LDEBUG << test(temp) ;
+ dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ;
+
+ DLIB_TEST_MSG(approx_equal(test(temp), dist(k,temp,val)), test(temp) - dist(k,temp,val));
+ DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val)));
+ DLIB_TEST(approx_equal(test.get_distance_function()(temp2), dist(k,temp2,val)));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+ DLIB_TEST(approx_equal(test(test), 0));
+ DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0));
+
+ val2.clear();
+ val2[0] = 0;
+ val2[1] = 1;
+ val2[2] = 0;
+ val2[3] = 0;
+ val2[4] = b;
+ for (unsigned int i = 0; i < 5; ++i) val[i] += val2[i];
+ temp2.clear();
+ temp2[1] = 1;
+ // make test store the point val
+ test.train(temp2, 1,1);
+
+ temp.clear();
+ temp[0] = 1;
+ temp[2] = 3;
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST_MSG(approx_equal(test(temp2), dist(k,temp2,val), 1e-7),
+ test(temp2) - dist(k,temp2,val));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+
+
+ val2.clear();
+ val2[0] = 0;
+ val2[1] = 1;
+ val2[2] = 2.6;
+ val2[3] = 8;
+ val2[4] = b;
+ for (unsigned int i = 0; i < 5; ++i) val[i] += val2[i];
+
+ temp2.clear();
+ temp2[0] = 0;
+ temp2[1] = 1;
+ temp2[2] = 2.6;
+ temp2[3] = 8;
+ // make test store the point val
+ test.train(temp2, 1,1);
+
+ temp.clear();
+ temp[0] = 1;
+ temp[1] = 1;
+ temp[2] = 3;
+ temp[3] = 0;
+ DLIB_TEST(approx_equal(test(temp), dist(k,temp,val)));
+ DLIB_TEST_MSG(approx_equal(test(temp2), dist(k,temp2,val)), test(temp2) - dist(k,temp2,val));
+ DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val)));
+ DLIB_TEST(approx_equal(test.inner_product(test), length_squared(val)));
+ DLIB_TEST_MSG(approx_equal(test(test), 0, 1e-6), test(test));
+ DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class kcentroid_tester : public tester
+ {
+ public:
+ kcentroid_tester (
+ ) :
+ tester ("test_kcentroid",
+ "Runs tests on the kcentroid components.")
+ {}
+
+ void perform_test (
+ )
+ {
+ // The idea here is to exercize all the various overloads of the kcentroid object. We also want
+ // to exercize the non-overloaded default version. That is why we have these unopt_* linear
+ // kernels
+ test_kcentroid_with_linear_kernel<linear_kernel<matrix<double,5,1> > >();
+ test_kcentroid_with_offset_linear_kernel<offset_kernel<linear_kernel<matrix<double,4,1> > > >();
+ test_kcentroid_with_linear_kernel<unopt_linear_kernel<matrix<double,5,1> > >();
+ test_kcentroid_with_offset_linear_kernel<offset_kernel<unopt_linear_kernel<matrix<double,4,1> > > >();
+ test_kcentroid_with_sparse_linear_kernel<sparse_linear_kernel<std::map<unsigned long,double> > >();
+ test_kcentroid_with_offset_sparse_linear_kernel<offset_kernel<sparse_linear_kernel<std::map<unsigned long,double> > > >();
+ test_kcentroid_with_sparse_linear_kernel<unopt_sparse_linear_kernel<std::map<unsigned long,double> > >();
+ test_kcentroid_with_offset_sparse_linear_kernel<offset_kernel<unopt_sparse_linear_kernel<std::map<unsigned long,double> > > >();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/kernel_matrix.cpp b/ml/dlib/dlib/test/kernel_matrix.cpp
new file mode 100644
index 000000000..8fc3a2d2c
--- /dev/null
+++ b/ml/dlib/dlib/test/kernel_matrix.cpp
@@ -0,0 +1,161 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm.h>
+#include <vector>
+#include <sstream>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.kernel_matrix");
+
+
+ class kernel_matrix_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ kernel_matrix_tester (
+ ) :
+ tester (
+ "test_kernel_matrix", // the command line argument name for this test
+ "Run tests on the kernel_matrix functions.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+
+ typedef matrix<double,0,1> sample_type;
+ typedef radial_basis_kernel<sample_type> kernel_type;
+ kernel_type kern(0.1);
+
+ std::vector<sample_type> vect1;
+ std::vector<sample_type> vect2;
+
+ const sample_type samp = randm(4,1);
+ sample_type samp2, samp3;
+
+ vect1.push_back(randm(4,1));
+ vect1.push_back(randm(4,1));
+ vect1.push_back(randm(4,1));
+ vect1.push_back(randm(4,1));
+
+ vect2.push_back(randm(4,1));
+ vect2.push_back(randm(4,1));
+ vect2.push_back(randm(4,1));
+ vect2.push_back(randm(4,1));
+ vect2.push_back(randm(4,1));
+
+ matrix<double> K;
+
+ K.set_size(vect1.size(), vect2.size());
+ for (long r = 0; r < K.nr(); ++r)
+ {
+ for (long c = 0; c < K.nc(); ++c)
+ {
+ K(r,c) = kern(vect1[r], vect2[c]);
+ }
+ }
+ DLIB_TEST(equal(K, kernel_matrix(kern, vect1, vect2)));
+ DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect1), mat(vect2))));
+
+
+ K.set_size(vect2.size(), vect1.size());
+ for (long r = 0; r < K.nr(); ++r)
+ {
+ for (long c = 0; c < K.nc(); ++c)
+ {
+ K(r,c) = kern(vect2[r], vect1[c]);
+ }
+ }
+ DLIB_TEST(equal(K, kernel_matrix(kern, vect2, vect1)));
+ DLIB_TEST(equal(K, tmp(kernel_matrix(kern, vect2, vect1))));
+ DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect2), mat(vect1))));
+
+
+ K.set_size(vect1.size(), vect1.size());
+ for (long r = 0; r < K.nr(); ++r)
+ {
+ for (long c = 0; c < K.nc(); ++c)
+ {
+ K(r,c) = kern(vect1[r], vect1[c]);
+ }
+ }
+ DLIB_TEST(equal(K, kernel_matrix(kern, vect1, vect1)));
+ DLIB_TEST(equal(K, tmp(kernel_matrix(kern, vect1, vect1))));
+ DLIB_TEST(equal(K, kernel_matrix(kern, vect1)));
+ DLIB_TEST(equal(K, tmp(kernel_matrix(kern, vect1))));
+ DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect1), mat(vect1))));
+ DLIB_TEST(equal(K, tmp(kernel_matrix(kern, mat(vect1), mat(vect1)))));
+ DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect1))));
+ DLIB_TEST(equal(K, tmp(kernel_matrix(kern, mat(vect1)))));
+
+
+ K.set_size(vect1.size(),1);
+ for (long r = 0; r < K.nr(); ++r)
+ {
+ for (long c = 0; c < K.nc(); ++c)
+ {
+ K(r,c) = kern(vect1[r], samp);
+ }
+ }
+ DLIB_TEST(equal(K, kernel_matrix(kern, vect1, samp)));
+ DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect1), samp)));
+
+
+ K.set_size(1, vect1.size());
+ for (long r = 0; r < K.nr(); ++r)
+ {
+ for (long c = 0; c < K.nc(); ++c)
+ {
+ K(r,c) = kern(samp, vect1[c]);
+ }
+ }
+ DLIB_TEST(equal(K, kernel_matrix(kern, samp, vect1)));
+ DLIB_TEST(equal(K, kernel_matrix(kern, samp, mat(vect1))));
+ DLIB_TEST(equal(K, tmp(kernel_matrix(kern, samp, vect1))));
+ DLIB_TEST(equal(K, tmp(kernel_matrix(kern, samp, mat(vect1)))));
+
+
+
+ samp2 = samp;
+ samp3 = samp;
+
+ // test the alias detection
+ samp2 = kernel_matrix(kern, vect1, samp2);
+ DLIB_TEST(equal(samp2, kernel_matrix(kern, vect1, samp)));
+
+ samp3 = trans(kernel_matrix(kern, samp3, vect2));
+ DLIB_TEST(equal(samp3, trans(kernel_matrix(kern, samp, vect2))));
+
+
+ samp2 += kernel_matrix(kern, vect1, samp);
+ DLIB_TEST(equal(samp2, 2*kernel_matrix(kern, vect1, samp)));
+
+ samp3 += trans(kernel_matrix(kern, samp, vect2));
+ DLIB_TEST(equal(samp3, 2*trans(kernel_matrix(kern, samp, vect2))));
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ kernel_matrix_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/kmeans.cpp b/ml/dlib/dlib/test/kmeans.cpp
new file mode 100644
index 000000000..95c037b77
--- /dev/null
+++ b/ml/dlib/dlib/test/kmeans.cpp
@@ -0,0 +1,163 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/svm.h>
+#include <dlib/matrix.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.kmeans");
+
+ dlib::rand rnd;
+
+ template <typename sample_type>
+ void run_test(
+ const std::vector<sample_type>& seed_centers
+ )
+ {
+ print_spinner();
+
+
+ sample_type samp;
+
+ std::vector<sample_type> samples;
+
+
+ for (unsigned long j = 0; j < seed_centers.size(); ++j)
+ {
+ for (int i = 0; i < 250; ++i)
+ {
+ samp = randm(seed_centers[0].size(),1,rnd) - 0.5;
+ samples.push_back(samp + seed_centers[j]);
+ }
+ }
+
+ randomize_samples(samples);
+
+ {
+ std::vector<sample_type> centers;
+ pick_initial_centers(seed_centers.size(), centers, samples, linear_kernel<sample_type>());
+
+ find_clusters_using_kmeans(samples, centers);
+
+ DLIB_TEST(centers.size() == seed_centers.size());
+
+ std::vector<int> hits(centers.size(),0);
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ unsigned long best_idx = 0;
+ double best_dist = 1e100;
+ for (unsigned long j = 0; j < centers.size(); ++j)
+ {
+ if (length(samples[i] - centers[j]) < best_dist)
+ {
+ best_dist = length(samples[i] - centers[j]);
+ best_idx = j;
+ }
+ }
+ hits[best_idx]++;
+ }
+
+ for (unsigned long i = 0; i < hits.size(); ++i)
+ {
+ DLIB_TEST(hits[i] == 250);
+ }
+ }
+ {
+ std::vector<sample_type> centers;
+ pick_initial_centers(seed_centers.size(), centers, samples, linear_kernel<sample_type>());
+
+ find_clusters_using_angular_kmeans(samples, centers);
+
+ DLIB_TEST(centers.size() == seed_centers.size());
+
+ std::vector<int> hits(centers.size(),0);
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ unsigned long best_idx = 0;
+ double best_dist = 1e100;
+ for (unsigned long j = 0; j < centers.size(); ++j)
+ {
+ if (length(samples[i] - centers[j]) < best_dist)
+ {
+ best_dist = length(samples[i] - centers[j]);
+ best_idx = j;
+ }
+ }
+ hits[best_idx]++;
+ }
+
+ for (unsigned long i = 0; i < hits.size(); ++i)
+ {
+ DLIB_TEST(hits[i] == 250);
+ }
+ }
+ }
+
+
+ class test_kmeans : public tester
+ {
+ public:
+ test_kmeans (
+ ) :
+ tester ("test_kmeans",
+ "Runs tests on the find_clusters_using_kmeans() function.")
+ {}
+
+ void perform_test (
+ )
+ {
+ {
+ dlog << LINFO << "test dlib::vector<double,2>";
+ typedef dlib::vector<double,2> sample_type;
+ std::vector<sample_type> seed_centers;
+ seed_centers.push_back(sample_type(10,10));
+ seed_centers.push_back(sample_type(10,-10));
+ seed_centers.push_back(sample_type(-10,10));
+ seed_centers.push_back(sample_type(-10,-10));
+
+ run_test(seed_centers);
+ }
+ {
+ dlog << LINFO << "test dlib::vector<double,2>";
+ typedef dlib::vector<float,2> sample_type;
+ std::vector<sample_type> seed_centers;
+ seed_centers.push_back(sample_type(10,10));
+ seed_centers.push_back(sample_type(10,-10));
+ seed_centers.push_back(sample_type(-10,10));
+ seed_centers.push_back(sample_type(-10,-10));
+
+ run_test(seed_centers);
+ }
+ {
+ dlog << LINFO << "test dlib::matrix<double,3,1>";
+ typedef dlib::matrix<double,3,1> sample_type;
+ std::vector<sample_type> seed_centers;
+ sample_type samp;
+ samp = 10,10,0; seed_centers.push_back(samp);
+ samp = -10,10,1; seed_centers.push_back(samp);
+ samp = -10,-10,2; seed_centers.push_back(samp);
+
+ run_test(seed_centers);
+ }
+
+
+ }
+ } a;
+
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/learning_to_track.cpp b/ml/dlib/dlib/test/learning_to_track.cpp
new file mode 100644
index 000000000..730c01ba8
--- /dev/null
+++ b/ml/dlib/dlib/test/learning_to_track.cpp
@@ -0,0 +1,306 @@
+// Copyright (C) 2014 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+#include <dlib/rand.h>
+
+
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.learning_to_track");
+
+// ----------------------------------------------------------------------------------------
+
+ struct detection_dense
+ {
+ typedef struct track_dense track_type;
+ matrix<double,0,1> measurements;
+ };
+
+
+ struct track_dense
+ {
+ typedef matrix<double,0,1> feature_vector_type;
+
+ track_dense()
+ {
+ time_since_last_association = 0;
+ }
+
+ void get_similarity_features(const detection_dense det, feature_vector_type& feats) const
+ {
+ feats = abs(last_measurements - det.measurements);
+ }
+
+ void update_track(const detection_dense det)
+ {
+ last_measurements = det.measurements;
+ time_since_last_association = 0;
+ }
+
+ void propagate_track()
+ {
+ ++time_since_last_association;
+ }
+
+ matrix<double,0,1> last_measurements;
+ unsigned long time_since_last_association;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ struct detection_sparse
+ {
+ typedef struct track_sparse track_type;
+ matrix<double,0,1> measurements;
+ };
+
+
+ struct track_sparse
+ {
+ typedef std::vector<std::pair<unsigned long,double> > feature_vector_type;
+
+ track_sparse()
+ {
+ time_since_last_association = 0;
+ }
+
+ void get_similarity_features(const detection_sparse det, feature_vector_type& feats) const
+ {
+ matrix<double,0,1> temp = abs(last_measurements - det.measurements);
+ feats.clear();
+ for (long i = 0; i < temp.size(); ++i)
+ feats.push_back(make_pair(i, temp(i)));
+ }
+
+ void update_track(const detection_sparse det)
+ {
+ last_measurements = det.measurements;
+ time_since_last_association = 0;
+ }
+
+ void propagate_track()
+ {
+ ++time_since_last_association;
+ }
+
+ matrix<double,0,1> last_measurements;
+ unsigned long time_since_last_association;
+ };
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ dlib::rand rnd;
+ const long num_objects = 4;
+ const long num_properties = 6;
+ std::vector<matrix<double,0,1> > object_properties(num_objects);
+
+ void initialize_object_properties()
+ {
+ rnd.set_seed("23ja2oirfjaf");
+ for (unsigned long i = 0; i < object_properties.size(); ++i)
+ object_properties[i] = randm(num_properties,1,rnd);
+ }
+
+ template <typename detection>
+ detection sample_detection_from_sensor(long object_id)
+ {
+ DLIB_CASSERT(object_id < num_objects,
+ "You can't ask to sample a detection from an object that doesn't exist.");
+ detection temp;
+ // Set the measurements equal to the object's true property values plus a little bit of
+ // noise.
+ temp.measurements = object_properties[object_id] + randm(num_properties,1,rnd)*0.1;
+ return temp;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+
+ template <typename detection>
+ std::vector<std::vector<labeled_detection<detection> > > make_random_tracking_data_for_training()
+ {
+ typedef std::vector<labeled_detection<detection> > detections_at_single_time_step;
+ typedef std::vector<detections_at_single_time_step> track_history;
+
+ track_history data;
+
+ // At each time step we get a set of detections from the objects in the world.
+ // Simulate 100 time steps worth of data where there are 3 objects present.
+ const int num_time_steps = 100;
+ for (int i = 0; i < num_time_steps; ++i)
+ {
+ detections_at_single_time_step dets(3);
+ // sample a detection from object 0
+ dets[0].det = sample_detection_from_sensor<detection>(0);
+ dets[0].label = 0;
+
+ // sample a detection from object 1
+ dets[1].det = sample_detection_from_sensor<detection>(1);
+ dets[1].label = 1;
+
+ // sample a detection from object 2
+ dets[2].det = sample_detection_from_sensor<detection>(2);
+ dets[2].label = 2;
+
+ randomize_samples(dets, rnd);
+ data.push_back(dets);
+ }
+
+ // Now let's imagine object 1 and 2 are gone but a new object, object 3 has arrived.
+ for (int i = 0; i < num_time_steps; ++i)
+ {
+ detections_at_single_time_step dets(2);
+ // sample a detection from object 0
+ dets[0].det = sample_detection_from_sensor<detection>(0);
+ dets[0].label = 0;
+
+ // sample a detection from object 3
+ dets[1].det = sample_detection_from_sensor<detection>(3);
+ dets[1].label = 3;
+
+ randomize_samples(dets, rnd);
+ data.push_back(dets);
+ }
+
+ return data;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename detection>
+ std::vector<detection> make_random_detections(long num_dets)
+ {
+ DLIB_CASSERT(num_dets <= num_objects,
+ "You can't ask for more detections than there are objects in our little simulation.");
+
+ std::vector<detection> dets(num_dets);
+ for (unsigned long i = 0; i < dets.size(); ++i)
+ {
+ dets[i] = sample_detection_from_sensor<detection>(i);
+ }
+ randomize_samples(dets, rnd);
+ return dets;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename detection>
+ void test_tracking_stuff()
+ {
+ print_spinner();
+
+
+ typedef std::vector<labeled_detection<detection> > detections_at_single_time_step;
+ typedef std::vector<detections_at_single_time_step> track_history;
+ std::vector<track_history> data;
+ data.push_back(make_random_tracking_data_for_training<detection>());
+ data.push_back(make_random_tracking_data_for_training<detection>());
+ data.push_back(make_random_tracking_data_for_training<detection>());
+ data.push_back(make_random_tracking_data_for_training<detection>());
+ data.push_back(make_random_tracking_data_for_training<detection>());
+
+
+ structural_track_association_trainer trainer;
+ trainer.set_c(1000);
+ track_association_function<detection> assoc = trainer.train(data);
+
+ double test_val = test_track_association_function(assoc, data);
+ DLIB_TEST_MSG( test_val == 1, test_val);
+ test_val = cross_validate_track_association_trainer(trainer, data, 5);
+ DLIB_TEST_MSG ( test_val == 1, test_val);
+
+
+
+ typedef typename detection::track_type track;
+ std::vector<track> tracks;
+
+ std::vector<detection> dets = make_random_detections<detection>(3);
+ assoc(tracks, dets);
+ DLIB_TEST(tracks.size() == 3);
+
+ dets = make_random_detections<detection>(3);
+ assoc(tracks, dets);
+ DLIB_TEST(tracks.size() == 3);
+
+ dets = make_random_detections<detection>(3);
+ assoc(tracks, dets);
+ DLIB_TEST(tracks.size() == 3);
+
+ dets = make_random_detections<detection>(4);
+ assoc(tracks, dets);
+ DLIB_TEST(tracks.size() == 4);
+
+ dets = make_random_detections<detection>(3);
+ assoc(tracks, dets);
+ DLIB_TEST(tracks.size() == 4);
+ unsigned long total_miss = 0;
+ for (unsigned long i = 0; i < tracks.size(); ++i)
+ total_miss += tracks[i].time_since_last_association;
+ DLIB_TEST(total_miss == 1);
+
+ dets = make_random_detections<detection>(3);
+ assoc(tracks, dets);
+ DLIB_TEST(tracks.size() == 4);
+ total_miss = 0;
+ unsigned long num_zero = 0;
+ for (unsigned long i = 0; i < tracks.size(); ++i)
+ {
+ total_miss += tracks[i].time_since_last_association;
+ if (tracks[i].time_since_last_association == 0)
+ ++num_zero;
+ }
+ DLIB_TEST(total_miss == 2);
+ DLIB_TEST(num_zero == 3);
+
+
+
+ ostringstream sout;
+ serialize(assoc, sout);
+
+ istringstream sin(sout.str());
+ deserialize(assoc, sin);
+ DLIB_TEST( test_track_association_function(assoc, data) == 1);
+ }
+
+
+// ----------------------------------------------------------------------------------------
+
+ class test_learning_to_track : public tester
+ {
+ public:
+ test_learning_to_track (
+ ) :
+ tester ("test_learning_to_track",
+ "Runs tests on the assignment learning code.")
+ {}
+
+ void perform_test (
+ )
+ {
+ initialize_object_properties();
+ for (int i = 0; i < 3; ++i)
+ {
+ dlog << LINFO << "run test_tracking_stuff<detection_dense>()";
+ test_tracking_stuff<detection_dense>();
+ dlog << LINFO << "run test_tracking_stuff<detection_sparse>()";
+ test_tracking_stuff<detection_sparse>();
+ }
+ }
+ } a;
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+
diff --git a/ml/dlib/dlib/test/least_squares.cpp b/ml/dlib/dlib/test/least_squares.cpp
new file mode 100644
index 000000000..c4282ad05
--- /dev/null
+++ b/ml/dlib/dlib/test/least_squares.cpp
@@ -0,0 +1,452 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/optimization.h>
+#include "optimization_test_functions.h"
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../rand.h"
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ using namespace dlib::test_functions;
+
+ logger dlog("test.least_squares");
+
+// ----------------------------------------------------------------------------------------
+
+ void test_with_chebyquad()
+ {
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(2);
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "chebyquad 2 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 2 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 2 error: " << length(ch - chebyquad_solution(2));
+
+ DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5);
+
+ }
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(2);
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "LM chebyquad 2 obj: " << chebyquad(ch);
+ dlog << LINFO << "LM chebyquad 2 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "LM chebyquad 2 error: " << length(ch - chebyquad_solution(2));
+
+ DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5);
+
+ }
+
+ print_spinner();
+ {
+ matrix<double,2,1> ch;
+
+ ch = chebyquad_start(2);
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "chebyquad 2 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 2 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 2 error: " << length(ch - chebyquad_solution(2));
+
+ DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,2,1> ch;
+
+ ch = chebyquad_start(2);
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "LM chebyquad 2 obj: " << chebyquad(ch);
+ dlog << LINFO << "LM chebyquad 2 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "LM chebyquad 2 error: " << length(ch - chebyquad_solution(2));
+
+ DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5);
+
+ }
+
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(4);
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "chebyquad 4 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 4 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 4 error: " << length(ch - chebyquad_solution(4));
+
+ DLIB_TEST(length(ch - chebyquad_solution(4)) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(4);
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "LM chebyquad 4 obj: " << chebyquad(ch);
+ dlog << LINFO << "LM chebyquad 4 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "LM chebyquad 4 error: " << length(ch - chebyquad_solution(4));
+
+ DLIB_TEST(length(ch - chebyquad_solution(4)) < 1e-5);
+
+ }
+
+
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(6);
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "chebyquad 6 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 6 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 6 error: " << length(ch - chebyquad_solution(6));
+
+ // the ch variable contains a permutation of what is in chebyquad_solution(6).
+ // Apparently there is more than one minimum?. Just check that the objective
+ // goes to zero.
+ DLIB_TEST(chebyquad(ch) < 1e-10);
+
+ }
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(6);
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "LM chebyquad 6 obj: " << chebyquad(ch);
+ dlog << LINFO << "LM chebyquad 6 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "LM chebyquad 6 error: " << length(ch - chebyquad_solution(6));
+
+ DLIB_TEST(chebyquad(ch) < 1e-10);
+
+ }
+
+
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(8);
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "chebyquad 8 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 8 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 8 error: " << length(ch - chebyquad_solution(8));
+
+ DLIB_TEST(length(ch - chebyquad_solution(8)) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(8);
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ chebyquad_residual,
+ derivative(chebyquad_residual),
+ range(0,ch.size()-1),
+ ch);
+
+ dlog << LINFO << "LM chebyquad 8 obj: " << chebyquad(ch);
+ dlog << LINFO << "LM chebyquad 8 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "LM chebyquad 8 error: " << length(ch - chebyquad_solution(8));
+
+ DLIB_TEST(length(ch - chebyquad_solution(8)) < 1e-5);
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_with_brown()
+ {
+ print_spinner();
+ {
+ matrix<double,4,1> ch;
+
+ ch = brown_start();
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 300),
+ brown_residual,
+ derivative(brown_residual),
+ range(1,20),
+ ch);
+
+ dlog << LINFO << "brown obj: " << brown(ch);
+ dlog << LINFO << "brown der: " << length(brown_derivative(ch));
+ dlog << LINFO << "brown error: " << length(ch - brown_solution());
+
+ DLIB_TEST_MSG(length(ch - brown_solution()) < 1e-5,length(ch - brown_solution()) );
+
+ }
+ print_spinner();
+ {
+ matrix<double,4,1> ch;
+
+ ch = brown_start();
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ brown_residual,
+ derivative(brown_residual),
+ range(1,20),
+ ch);
+
+ dlog << LINFO << "LM brown obj: " << brown(ch);
+ dlog << LINFO << "LM brown der: " << length(brown_derivative(ch));
+ dlog << LINFO << "LM brown error: " << length(ch - brown_solution());
+
+ DLIB_TEST(length(ch - brown_solution()) < 1e-5);
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+// These functions are declared here because wrapping the real rosen functions in this
+// way avoids triggering a bug in visual studio 2005 which prevents this code from compiling.
+ double rosen_residual_double (int i, const matrix<double,2,1>& m)
+ { return rosen_residual(i,m); }
+ float rosen_residual_float (int i, const matrix<float,2,1>& m)
+ { return rosen_residual(i,m); }
+
+ matrix<double,2,1> rosen_residual_derivative_double (int i, const matrix<double,2,1>& m)
+ { return rosen_residual_derivative(i,m); }
+ /*
+ matrix<float,2,1> rosen_residual_derivative_float (int i, const matrix<float,2,1>& m)
+ { return rosen_residual_derivative(i,m); }
+ */
+
+ double rosen_big_residual_double (int i, const matrix<double,2,1>& m)
+ { return rosen_big_residual(i,m); }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_with_rosen()
+ {
+
+ print_spinner();
+ {
+ matrix<double,2,1> ch;
+
+ ch = rosen_start<double>();
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ rosen_residual_double,
+ rosen_residual_derivative_double,
+ range(1,20),
+ ch);
+
+ dlog << LINFO << "rosen obj: " << rosen(ch);
+ dlog << LINFO << "rosen error: " << length(ch - rosen_solution<double>());
+
+ DLIB_TEST(length(ch - rosen_solution<double>()) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,2,1> ch;
+
+ ch = rosen_start<double>();
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ rosen_residual_double,
+ rosen_residual_derivative_double,
+ range(1,20),
+ ch);
+
+ dlog << LINFO << "lm rosen obj: " << rosen(ch);
+ dlog << LINFO << "lm rosen error: " << length(ch - rosen_solution<double>());
+
+ DLIB_TEST(length(ch - rosen_solution<double>()) < 1e-5);
+
+ }
+
+
+
+ print_spinner();
+ {
+ matrix<double,2,1> ch;
+
+ ch = rosen_start<double>();
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ rosen_residual_double,
+ derivative(rosen_residual_double),
+ range(1,20),
+ ch);
+
+ dlog << LINFO << "rosen obj: " << rosen(ch);
+ dlog << LINFO << "rosen error: " << length(ch - rosen_solution<double>());
+
+ DLIB_TEST(length(ch - rosen_solution<double>()) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<float,2,1> ch;
+
+ ch = rosen_start<float>();
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ rosen_residual_float,
+ derivative(rosen_residual_float),
+ range(1,20),
+ ch);
+
+ dlog << LINFO << "float rosen obj: " << rosen(ch);
+ dlog << LINFO << "float rosen error: " << length(ch - rosen_solution<float>());
+
+ DLIB_TEST(length(ch - rosen_solution<float>()) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<float,2,1> ch;
+
+ ch = rosen_start<float>();
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ rosen_residual_float,
+ derivative(rosen_residual_float),
+ range(1,20),
+ ch);
+
+ dlog << LINFO << "LM float rosen obj: " << rosen(ch);
+ dlog << LINFO << "LM float rosen error: " << length(ch - rosen_solution<float>());
+
+ DLIB_TEST(length(ch - rosen_solution<float>()) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,2,1> ch;
+
+ ch = rosen_start<double>();
+
+ solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80),
+ rosen_residual_double,
+ derivative(rosen_residual_double),
+ range(1,20),
+ ch);
+
+ dlog << LINFO << "LM rosen obj: " << rosen(ch);
+ dlog << LINFO << "LM rosen error: " << length(ch - rosen_solution<double>());
+
+ DLIB_TEST(length(ch - rosen_solution<double>()) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,2,1> ch;
+
+ ch = rosen_big_start<double>();
+
+ solve_least_squares(objective_delta_stop_strategy(1e-13, 80),
+ rosen_big_residual_double,
+ derivative(rosen_big_residual_double),
+ range(1,2),
+ ch);
+
+ dlog << LINFO << "rosen big obj: " << rosen_big(ch);
+ dlog << LINFO << "rosen big error: " << length(ch - rosen_big_solution<double>());
+
+ DLIB_TEST(length(ch - rosen_big_solution<double>()) < 1e-5);
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class optimization_tester : public tester
+ {
+ public:
+ optimization_tester (
+ ) :
+ tester ("test_least_squares",
+ "Runs tests on the least squares optimization component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_with_chebyquad();
+ test_with_brown();
+ test_with_rosen();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/linear_manifold_regularizer.cpp b/ml/dlib/dlib/test/linear_manifold_regularizer.cpp
new file mode 100644
index 000000000..e73b1c8d3
--- /dev/null
+++ b/ml/dlib/dlib/test/linear_manifold_regularizer.cpp
@@ -0,0 +1,408 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/manifold_regularization.h>
+#include <dlib/svm.h>
+#include <dlib/rand.h>
+#include <dlib/string.h>
+#include <dlib/graph_utils_threaded.h>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.linear_manifold_regularizer");
+
+ template <typename hash_type, typename samples_type>
+ void test_find_k_nearest_neighbors_lsh(
+ const samples_type& samples
+ )
+ {
+ std::vector<sample_pair> edges1, edges2;
+
+ find_k_nearest_neighbors(samples, cosine_distance(), 2, edges1);
+ find_k_nearest_neighbors_lsh(samples, cosine_distance(), hash_type(), 2, 6, edges2, 2);
+
+ std::sort(edges1.begin(), edges1.end(), order_by_index<sample_pair>);
+ std::sort(edges2.begin(), edges2.end(), order_by_index<sample_pair>);
+
+ DLIB_TEST_MSG(edges1.size() == edges2.size(), edges1.size() << " " << edges2.size());
+ for (unsigned long i = 0; i < edges1.size(); ++i)
+ {
+ DLIB_TEST(edges1[i] == edges2[i]);
+ DLIB_TEST_MSG(std::abs(edges1[i].distance() - edges2[i].distance()) < 1e-7,
+ edges1[i].distance() - edges2[i].distance());
+ }
+ }
+
+ template <typename scalar_type>
+ void test_knn_lsh_sparse()
+ {
+ dlib::rand rnd;
+ std::vector<std::map<unsigned long,scalar_type> > samples;
+ samples.resize(20);
+ for (unsigned int i = 0; i < samples.size(); ++i)
+ {
+ samples[i][0] = rnd.get_random_gaussian();
+ samples[i][2] = rnd.get_random_gaussian();
+ }
+
+ test_find_k_nearest_neighbors_lsh<hash_similar_angles_64>(samples);
+ test_find_k_nearest_neighbors_lsh<hash_similar_angles_128>(samples);
+ test_find_k_nearest_neighbors_lsh<hash_similar_angles_256>(samples);
+ test_find_k_nearest_neighbors_lsh<hash_similar_angles_512>(samples);
+ }
+
+ template <typename scalar_type>
+ void test_knn_lsh_dense()
+ {
+ dlib::rand rnd;
+ std::vector<matrix<scalar_type,0,1> > samples;
+ samples.resize(20);
+ for (unsigned int i = 0; i < samples.size(); ++i)
+ {
+ samples[i].set_size(2);
+ samples[i](0) = rnd.get_random_gaussian();
+ samples[i](1) = rnd.get_random_gaussian();
+ }
+
+ test_find_k_nearest_neighbors_lsh<hash_similar_angles_64>(samples);
+ test_find_k_nearest_neighbors_lsh<hash_similar_angles_128>(samples);
+ test_find_k_nearest_neighbors_lsh<hash_similar_angles_256>(samples);
+ test_find_k_nearest_neighbors_lsh<hash_similar_angles_512>(samples);
+ }
+
+
+
+ class linear_manifold_regularizer_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ linear_manifold_regularizer_tester (
+ ) :
+ tester (
+ "test_linear_manifold_regularizer", // the command line argument name for this test
+ "Run tests on the linear_manifold_regularizer object.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ seed = 1;
+ }
+
+ dlib::rand rnd;
+
+ unsigned long seed;
+
+ typedef matrix<double, 0, 1> sample_type;
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+ void do_the_test()
+ {
+ print_spinner();
+ std::vector<sample_type> samples;
+
+ // Declare an instance of the kernel we will be using.
+ const kernel_type kern(0.1);
+
+ const unsigned long num_points = 200;
+
+ // create a large dataset with two concentric circles.
+ generate_circle(samples, 1, num_points); // circle of radius 1
+ generate_circle(samples, 5, num_points); // circle of radius 5
+
+ std::vector<sample_pair> edges;
+ find_percent_shortest_edges_randomly(samples, squared_euclidean_distance(0.1, 4), 1, 10000, "random seed", edges);
+
+ dlog << LTRACE << "number of edges generated: " << edges.size();
+
+ empirical_kernel_map<kernel_type> ekm;
+
+ ekm.load(kern, randomly_subsample(samples, 100));
+
+ // Project all the samples into the span of our 50 basis samples
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ samples[i] = ekm.project(samples[i]);
+
+
+ // Now create the manifold regularizer. The result is a transformation matrix that
+ // embodies the manifold assumption discussed above.
+ linear_manifold_regularizer<sample_type> lmr;
+ lmr.build(samples, edges, use_gaussian_weights(0.1));
+ matrix<double> T = lmr.get_transformation_matrix(10000);
+
+ print_spinner();
+
+ // generate the T matrix manually and make sure it matches. The point of this test
+ // is to make sure that the more complex version of this that happens inside the linear_manifold_regularizer
+ // is correct. It uses a tedious block of loops to do it in a way that is a lot faster for sparse
+ // W matrices but isn't super straight forward.
+ matrix<double> X(samples[0].size(), samples.size());
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ set_colm(X,i) = samples[i];
+
+ matrix<double> W(samples.size(), samples.size());
+ W = 0;
+ for (unsigned long i = 0; i < edges.size(); ++i)
+ {
+ W(edges[i].index1(), edges[i].index2()) = use_gaussian_weights(0.1)(edges[i]);
+ W(edges[i].index2(), edges[i].index1()) = use_gaussian_weights(0.1)(edges[i]);
+ }
+ matrix<double> L = diagm(sum_rows(W)) - W;
+ matrix<double> trueT = inv_lower_triangular(chol(identity_matrix<double>(X.nr()) + (10000.0/sum(lowerm(W)))*X*L*trans(X)));
+
+ dlog << LTRACE << "T error: "<< max(abs(T - trueT));
+ DLIB_TEST(max(abs(T - trueT)) < 1e-7);
+
+
+ print_spinner();
+ // Apply the transformation generated by the linear_manifold_regularizer to
+ // all our samples.
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ samples[i] = T*samples[i];
+
+
+ // For convenience, generate a projection_function and merge the transformation
+ // matrix T into it.
+ projection_function<kernel_type> proj = ekm.get_projection_function();
+ proj.weights = T*proj.weights;
+
+
+ // Pick 2 different labeled points. One on the inner circle and another on the outer.
+ // For each of these test points we will see if using the single plane that separates
+ // them is a good way to separate the concentric circles. Also do this a bunch
+ // of times with different randomly chosen points so we can see how robust the result is.
+ for (int itr = 0; itr < 10; ++itr)
+ {
+ print_spinner();
+ std::vector<sample_type> test_points;
+ // generate a random point from the radius 1 circle
+ generate_circle(test_points, 1, 1);
+ // generate a random point from the radius 5 circle
+ generate_circle(test_points, 5, 1);
+
+ // project the two test points into kernel space. Recall that this projection_function
+ // has the manifold regularizer incorporated into it.
+ const sample_type class1_point = proj(test_points[0]);
+ const sample_type class2_point = proj(test_points[1]);
+
+ double num_wrong = 0;
+
+ // Now attempt to classify all the data samples according to which point
+ // they are closest to. The output of this program shows that without manifold
+ // regularization this test will fail but with it it will perfectly classify
+ // all the points.
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ double distance_to_class1 = length(samples[i] - class1_point);
+ double distance_to_class2 = length(samples[i] - class2_point);
+
+ bool predicted_as_class_1 = (distance_to_class1 < distance_to_class2);
+
+ bool really_is_class_1 = (i < num_points);
+
+ // now count how many times we make a mistake
+ if (predicted_as_class_1 != really_is_class_1)
+ ++num_wrong;
+ }
+
+ DLIB_TEST_MSG(num_wrong == 0, num_wrong);
+ }
+
+ }
+
+ void generate_circle (
+ std::vector<sample_type>& samples,
+ double radius,
+ const long num
+ )
+ {
+ sample_type m(2,1);
+
+ for (long i = 0; i < num; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ samples.push_back(m);
+ }
+ }
+
+
+ void test_knn1()
+ {
+ std::vector<matrix<double,2,1> > samples;
+
+ matrix<double,2,1> test;
+
+ test = 0,0; samples.push_back(test);
+ test = 1,1; samples.push_back(test);
+ test = 1,-1; samples.push_back(test);
+ test = -1,1; samples.push_back(test);
+ test = -1,-1; samples.push_back(test);
+
+ std::vector<sample_pair> edges;
+ find_k_nearest_neighbors(samples, squared_euclidean_distance(), 1, edges);
+ DLIB_TEST(edges.size() == 4);
+
+ std::sort(edges.begin(), edges.end(), &order_by_index<sample_pair>);
+
+ DLIB_TEST(edges[0] == sample_pair(0,1,0));
+ DLIB_TEST(edges[1] == sample_pair(0,2,0));
+ DLIB_TEST(edges[2] == sample_pair(0,3,0));
+ DLIB_TEST(edges[3] == sample_pair(0,4,0));
+
+ find_k_nearest_neighbors(samples, squared_euclidean_distance(), 3, edges);
+ DLIB_TEST(edges.size() == 8);
+
+ find_k_nearest_neighbors(samples, squared_euclidean_distance(3.9, 4.1), 3, edges);
+ DLIB_TEST(edges.size() == 4);
+
+ std::sort(edges.begin(), edges.end(), &order_by_index<sample_pair>);
+
+ DLIB_TEST(edges[0] == sample_pair(1,2,0));
+ DLIB_TEST(edges[1] == sample_pair(1,3,0));
+ DLIB_TEST(edges[2] == sample_pair(2,4,0));
+ DLIB_TEST(edges[3] == sample_pair(3,4,0));
+
+ find_k_nearest_neighbors(samples, squared_euclidean_distance(30000, 4.1), 3, edges);
+ DLIB_TEST(edges.size() == 0);
+ }
+
+ void test_knn1_approx()
+ {
+ std::vector<matrix<double,2,1> > samples;
+
+ matrix<double,2,1> test;
+
+ test = 0,0; samples.push_back(test);
+ test = 1,1; samples.push_back(test);
+ test = 1,-1; samples.push_back(test);
+ test = -1,1; samples.push_back(test);
+ test = -1,-1; samples.push_back(test);
+
+ std::vector<sample_pair> edges;
+ find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(), 1, 10000, seed, edges);
+ DLIB_TEST(edges.size() == 4);
+
+ std::sort(edges.begin(), edges.end(), &order_by_index<sample_pair>);
+
+ DLIB_TEST(edges[0] == sample_pair(0,1,0));
+ DLIB_TEST(edges[1] == sample_pair(0,2,0));
+ DLIB_TEST(edges[2] == sample_pair(0,3,0));
+ DLIB_TEST(edges[3] == sample_pair(0,4,0));
+
+ find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(), 3, 10000, seed, edges);
+ DLIB_TEST(edges.size() == 8);
+
+ find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(3.9, 4.1), 3, 10000, seed, edges);
+ DLIB_TEST(edges.size() == 4);
+
+ std::sort(edges.begin(), edges.end(), &order_by_index<sample_pair>);
+
+ DLIB_TEST(edges[0] == sample_pair(1,2,0));
+ DLIB_TEST(edges[1] == sample_pair(1,3,0));
+ DLIB_TEST(edges[2] == sample_pair(2,4,0));
+ DLIB_TEST(edges[3] == sample_pair(3,4,0));
+
+ find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(30000, 4.1), 3, 10000, seed, edges);
+ DLIB_TEST(edges.size() == 0);
+ }
+
+ void test_knn2()
+ {
+ std::vector<matrix<double,2,1> > samples;
+
+ matrix<double,2,1> test;
+
+ test = 1,1; samples.push_back(test);
+ test = 1,-1; samples.push_back(test);
+ test = -1,1; samples.push_back(test);
+ test = -1,-1; samples.push_back(test);
+
+ std::vector<sample_pair> edges;
+ find_k_nearest_neighbors(samples, squared_euclidean_distance(), 2, edges);
+ DLIB_TEST(edges.size() == 4);
+
+ std::sort(edges.begin(), edges.end(), &order_by_index<sample_pair>);
+
+ DLIB_TEST(edges[0] == sample_pair(0,1,0));
+ DLIB_TEST(edges[1] == sample_pair(0,2,0));
+ DLIB_TEST(edges[2] == sample_pair(1,3,0));
+ DLIB_TEST(edges[3] == sample_pair(2,3,0));
+
+ find_k_nearest_neighbors(samples, squared_euclidean_distance(), 200, edges);
+ DLIB_TEST(edges.size() == 4*3/2);
+ }
+
+ void test_knn2_approx()
+ {
+ std::vector<matrix<double,2,1> > samples;
+
+ matrix<double,2,1> test;
+
+ test = 1,1; samples.push_back(test);
+ test = 1,-1; samples.push_back(test);
+ test = -1,1; samples.push_back(test);
+ test = -1,-1; samples.push_back(test);
+
+ std::vector<sample_pair> edges;
+ // For this simple graph and high number of samples we will do we should obtain the exact
+ // knn solution.
+ find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(), 2, 10000, seed, edges);
+ DLIB_TEST(edges.size() == 4);
+
+ std::sort(edges.begin(), edges.end(), &order_by_index<sample_pair>);
+
+ DLIB_TEST(edges[0] == sample_pair(0,1,0));
+ DLIB_TEST(edges[1] == sample_pair(0,2,0));
+ DLIB_TEST(edges[2] == sample_pair(1,3,0));
+ DLIB_TEST(edges[3] == sample_pair(2,3,0));
+
+
+ find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(), 200, 10000, seed, edges);
+ DLIB_TEST(edges.size() == 4*3/2);
+ }
+
+ void perform_test (
+ )
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ do_the_test();
+
+ ++seed;
+ test_knn1_approx();
+ test_knn2_approx();
+ }
+ test_knn1();
+ test_knn2();
+ test_knn_lsh_sparse<double>();
+ test_knn_lsh_sparse<float>();
+ test_knn_lsh_dense<double>();
+ test_knn_lsh_dense<float>();
+
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ linear_manifold_regularizer_tester a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/lspi.cpp b/ml/dlib/dlib/test/lspi.cpp
new file mode 100644
index 000000000..013887115
--- /dev/null
+++ b/ml/dlib/dlib/test/lspi.cpp
@@ -0,0 +1,258 @@
+// Copyright (C) 2015 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/control.h>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.lspi");
+
+ template <bool have_prior>
+ struct chain_model
+ {
+ typedef int state_type;
+ typedef int action_type; // 0 is move left, 1 is move right
+ const static bool force_last_weight_to_1 = have_prior;
+
+
+ const static int num_states = 4; // not required in the model interface
+
+ matrix<double,8,1> offset;
+ chain_model()
+ {
+ offset =
+ 2.048 ,
+ 2.56 ,
+ 2.048 ,
+ 3.2 ,
+ 2.56 ,
+ 4 ,
+ 3.2,
+ 5 ;
+ if (!have_prior)
+ offset = 0;
+
+ }
+
+ unsigned long num_features(
+ ) const
+ {
+ if (have_prior)
+ return num_states*2 + 1;
+ else
+ return num_states*2;
+ }
+
+ action_type find_best_action (
+ const state_type& state,
+ const matrix<double,0,1>& w
+ ) const
+ {
+ if (w(state*2)+offset(state*2) >= w(state*2+1)+offset(state*2+1))
+ //if (w(state*2) >= w(state*2+1))
+ return 0;
+ else
+ return 1;
+ }
+
+ void get_features (
+ const state_type& state,
+ const action_type& action,
+ matrix<double,0,1>& feats
+ ) const
+ {
+ feats.set_size(num_features());
+ feats = 0;
+ feats(state*2 + action) = 1;
+ if (have_prior)
+ feats(num_features()-1) = offset(state*2+action);
+ }
+
+ };
+
+ void test_lspi_prior1()
+ {
+ print_spinner();
+ typedef process_sample<chain_model<true> > sample_type;
+ std::vector<sample_type> samples;
+
+ samples.push_back(sample_type(0,0,0,0));
+ samples.push_back(sample_type(0,1,1,0));
+
+ samples.push_back(sample_type(1,0,0,0));
+ samples.push_back(sample_type(1,1,2,0));
+
+ samples.push_back(sample_type(2,0,1,0));
+ samples.push_back(sample_type(2,1,3,0));
+
+ samples.push_back(sample_type(3,0,2,0));
+ samples.push_back(sample_type(3,1,3,1));
+
+
+ lspi<chain_model<true> > trainer;
+ //trainer.be_verbose();
+ trainer.set_lambda(0);
+ policy<chain_model<true> > pol = trainer.train(samples);
+
+ dlog << LINFO << pol.get_weights();
+
+ matrix<double,0,1> w = pol.get_weights();
+ DLIB_TEST(pol.get_weights().size() == 9);
+ DLIB_TEST(w(w.size()-1) == 1);
+ w(w.size()-1) = 0;
+ DLIB_TEST_MSG(length(w) < 1e-12, length(w));
+
+ dlog << LINFO << "action: " << pol(0);
+ dlog << LINFO << "action: " << pol(1);
+ dlog << LINFO << "action: " << pol(2);
+ dlog << LINFO << "action: " << pol(3);
+ DLIB_TEST(pol(0) == 1);
+ DLIB_TEST(pol(1) == 1);
+ DLIB_TEST(pol(2) == 1);
+ DLIB_TEST(pol(3) == 1);
+ }
+
+ void test_lspi_prior2()
+ {
+ print_spinner();
+ typedef process_sample<chain_model<true> > sample_type;
+ std::vector<sample_type> samples;
+
+ samples.push_back(sample_type(0,0,0,0));
+ samples.push_back(sample_type(0,1,1,0));
+
+ samples.push_back(sample_type(1,0,0,0));
+ samples.push_back(sample_type(1,1,2,0));
+
+ samples.push_back(sample_type(2,0,1,0));
+ samples.push_back(sample_type(2,1,3,1));
+
+ samples.push_back(sample_type(3,0,2,0));
+ samples.push_back(sample_type(3,1,3,0));
+
+
+ lspi<chain_model<true> > trainer;
+ //trainer.be_verbose();
+ trainer.set_lambda(0);
+ policy<chain_model<true> > pol = trainer.train(samples);
+
+
+ dlog << LINFO << "action: " << pol(0);
+ dlog << LINFO << "action: " << pol(1);
+ dlog << LINFO << "action: " << pol(2);
+ dlog << LINFO << "action: " << pol(3);
+ DLIB_TEST(pol(0) == 1);
+ DLIB_TEST(pol(1) == 1);
+ DLIB_TEST(pol(2) == 1);
+ DLIB_TEST(pol(3) == 0);
+ }
+
+ void test_lspi_noprior1()
+ {
+ print_spinner();
+ typedef process_sample<chain_model<false> > sample_type;
+ std::vector<sample_type> samples;
+
+ samples.push_back(sample_type(0,0,0,0));
+ samples.push_back(sample_type(0,1,1,0));
+
+ samples.push_back(sample_type(1,0,0,0));
+ samples.push_back(sample_type(1,1,2,0));
+
+ samples.push_back(sample_type(2,0,1,0));
+ samples.push_back(sample_type(2,1,3,0));
+
+ samples.push_back(sample_type(3,0,2,0));
+ samples.push_back(sample_type(3,1,3,1));
+
+
+ lspi<chain_model<false> > trainer;
+ //trainer.be_verbose();
+ trainer.set_lambda(0.01);
+ policy<chain_model<false> > pol = trainer.train(samples);
+
+ dlog << LINFO << pol.get_weights();
+ DLIB_TEST(pol.get_weights().size() == 8);
+
+
+ dlog << LINFO << "action: " << pol(0);
+ dlog << LINFO << "action: " << pol(1);
+ dlog << LINFO << "action: " << pol(2);
+ dlog << LINFO << "action: " << pol(3);
+ DLIB_TEST(pol(0) == 1);
+ DLIB_TEST(pol(1) == 1);
+ DLIB_TEST(pol(2) == 1);
+ DLIB_TEST(pol(3) == 1);
+ }
+ void test_lspi_noprior2()
+ {
+ print_spinner();
+ typedef process_sample<chain_model<false> > sample_type;
+ std::vector<sample_type> samples;
+
+ samples.push_back(sample_type(0,0,0,0));
+ samples.push_back(sample_type(0,1,1,0));
+
+ samples.push_back(sample_type(1,0,0,0));
+ samples.push_back(sample_type(1,1,2,1));
+
+ samples.push_back(sample_type(2,0,1,0));
+ samples.push_back(sample_type(2,1,3,0));
+
+ samples.push_back(sample_type(3,0,2,0));
+ samples.push_back(sample_type(3,1,3,0));
+
+
+ lspi<chain_model<false> > trainer;
+ //trainer.be_verbose();
+ trainer.set_lambda(0.01);
+ policy<chain_model<false> > pol = trainer.train(samples);
+
+ dlog << LINFO << pol.get_weights();
+ DLIB_TEST(pol.get_weights().size() == 8);
+
+
+ dlog << LINFO << "action: " << pol(0);
+ dlog << LINFO << "action: " << pol(1);
+ dlog << LINFO << "action: " << pol(2);
+ dlog << LINFO << "action: " << pol(3);
+ DLIB_TEST(pol(0) == 1);
+ DLIB_TEST(pol(1) == 1);
+ DLIB_TEST(pol(2) == 0);
+ DLIB_TEST(pol(3) == 0);
+ }
+
+ class lspi_tester : public tester
+ {
+ public:
+ lspi_tester (
+ ) :
+ tester (
+ "test_lspi", // the command line argument name for this test
+ "Run tests on the lspi object.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+ void perform_test (
+ )
+ {
+ test_lspi_prior1();
+ test_lspi_prior2();
+
+ test_lspi_noprior1();
+ test_lspi_noprior2();
+ }
+ };
+
+ lspi_tester a;
+}
+
diff --git a/ml/dlib/dlib/test/lz77_buffer.cpp b/ml/dlib/dlib/test/lz77_buffer.cpp
new file mode 100644
index 000000000..ccbb1a24c
--- /dev/null
+++ b/ml/dlib/dlib/test/lz77_buffer.cpp
@@ -0,0 +1,569 @@
+// Copyright (C) 2004 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <cstdlib>
+#include <dlib/sliding_buffer.h>
+
+#include <dlib/lz77_buffer.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.lz77_buffer");
+
+ template <
+ typename buf
+ >
+ void lz77_buffer_kernel_test (
+ )
+ /*!
+ requires
+ - buf is an implementation of lz77_buffer/lz77_buffer_kernel_abstract.h
+ ensures
+ - runs tests on buf for compliance with the specs
+ !*/
+ {
+ typedef dlib::sliding_buffer<unsigned char>::kernel_1a sbuf;
+
+ buf test(8,20);
+ srand(static_cast<unsigned int>(time(0)));
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,test.get_history_buffer_limit());
+ DLIB_TEST(test.get_lookahead_buffer_limit() == 20);
+
+
+ for (int g = 0; g < 2; ++g)
+ {
+ test.clear();
+
+ for (int i = 0; i < 1000; ++i)
+ {
+ test.add('a');
+ }
+ DLIB_TEST(test.get_lookahead_buffer_size() == 20);
+
+
+ test.shift_buffers(5);
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 15);
+
+
+
+ unsigned long index, length, temp;
+ temp = test.get_lookahead_buffer_size();
+ test.find_match(index,length,5);
+
+
+ DLIB_TEST_MSG(length <= temp,
+ "length: " << length <<
+ "\ntemp: " << temp);
+ DLIB_TEST(test.get_lookahead_buffer_size() <= 15);
+
+
+ }
+
+
+ for (int g = 0; g < 2; ++g)
+ {
+
+
+
+ test.clear();
+
+
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_limit() == 256-20);
+ DLIB_TEST(test.get_lookahead_buffer_limit() == 20);
+
+ unsigned long a,b, temp = test.get_lookahead_buffer_size();
+ test.find_match(a,b,0);
+ DLIB_TEST(b <= temp);
+ DLIB_TEST(b == 0);
+
+ test.find_match(a,b,5);
+ DLIB_TEST(b == 0);
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_limit() == 256-20);
+ DLIB_TEST(test.get_lookahead_buffer_limit() == 20);
+
+
+
+ ostringstream sout;
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_size() == 0,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_limit() == 20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_size() == 0,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_limit() == 20,);\n";
+ istringstream sin(sout.str());
+
+ sout.str("");
+ sout.clear();
+
+ unsigned char ch;
+ sbuf sbuffer;
+ sbuffer.set_size(8);
+
+
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch);
+ DLIB_TEST(test.get_lookahead_buffer_size() == 1);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST(test.get_lookahead_buffer_limit() == 20);
+
+
+
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch);
+ DLIB_TEST(test.get_lookahead_buffer_size() == 2);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST(test.get_lookahead_buffer_limit() == 20);
+
+
+
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch);
+ DLIB_TEST(test.get_lookahead_buffer_size() == 3);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+
+ // add 17 chars to test so that the lookahead buffer will be full
+ for (int i = 0; i < 17; ++i)
+ {
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch);
+ }
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 20);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST(test.lookahead_buffer(0) == sbuffer[20]);
+
+
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch);
+ DLIB_TEST(test.get_lookahead_buffer_size() == 20);
+ DLIB_TEST(test.get_history_buffer_size() == 1);
+
+
+
+
+
+
+ // add the above text to test and make sure it gives the correct results
+ ch = sin.get();
+ while (sin)
+ {
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch);
+ DLIB_TEST(test.history_buffer(0) == sbuffer[21]);
+ DLIB_TEST(test.history_buffer(1) == sbuffer[22]);
+
+ ch = sin.get();
+ }
+
+
+
+ // make sure the contents of lookahead_buffer and history_buffer
+ // match what is in sbuffer
+ sbuffer.rotate_right(1);
+ for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i));
+ }
+ for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i));
+ }
+ sbuffer.rotate_left(1);
+
+
+
+
+
+
+
+
+
+
+ sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0]
+
+ unsigned long match_index, match_length;
+ unsigned long ltemp = test.get_lookahead_buffer_size();
+ test.find_match(match_index,match_length,0);
+ DLIB_TEST(match_length <= ltemp);
+
+
+ // verify the match with sbuffer
+ for (unsigned int i = 0; i < match_length; ++i)
+ {
+ DLIB_TEST_MSG(sbuffer[19-i] == sbuffer[match_index+20-i],i);
+ }
+
+
+ sin.str("");
+ sin.clear();
+
+ } // for (int g = 0; g < 2; ++g)
+
+
+ for (int g = 0; g < 8; ++g)
+ {
+ test.clear();
+
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_limit() == 256-20);
+ DLIB_TEST(test.get_lookahead_buffer_limit() == 20);
+
+
+ sbuf sbuffer;
+ sbuffer.set_size(8);
+
+ ostringstream sout;
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_size() == 0,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_limit() == 20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_limit() == 20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n";
+ sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n";
+ istringstream sin(sout.str());
+
+ unsigned char ch;
+ for (int i = 0; i < 100; ++i)
+ {
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ }
+
+ // make sure the contents of lookahead_buffer and history_buffer
+ // match what is in sbuffer
+ sbuffer.rotate_right(1);
+ for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i));
+ }
+ for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i));
+ }
+ sbuffer.rotate_left(1);
+
+
+
+
+ unsigned long match_index, match_length;
+ unsigned long ltemp = test.get_lookahead_buffer_size();
+ test.find_match(match_index,match_length,0);
+ DLIB_TEST(match_length <= ltemp);
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 20-match_length);
+
+ sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0]
+ // verify the match with sbuffer
+ for (unsigned int i = 0; i < match_length; ++i)
+ {
+ DLIB_TEST(sbuffer[i+20-match_length] == sbuffer[i+1+match_index+20-match_length]);
+ }
+ sbuffer.rotate_left(1); // free up sbuffer[0] for new data
+
+
+
+
+ for (int i = 0; i < 7+g*2; ++i)
+ {
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ }
+
+ ch = '?';
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ ch = 'a';
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ ch = 'v';
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ ch = 'i';
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ ch = 's';
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+
+
+ // adjust sbuffer due to the last call to test.find_match()
+ // but only if we haven't already added enough (20 or more) chars
+ // to fill the lookahead buffer already.
+ if (match_length > static_cast<unsigned int>(12+g*2))
+ sbuffer.rotate_left(match_length-(12+g*2));
+
+
+
+
+
+ // make sure the contents of lookahead_buffer and history_buffer
+ // match what is in sbuffer
+ sbuffer.rotate_right(1);
+ for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i));
+ }
+ for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i));
+ }
+ sbuffer.rotate_left(1);
+
+
+
+
+ test.find_match(match_index,match_length,10+g);
+
+ if (match_length > 0)
+ DLIB_TEST(match_length >= static_cast<unsigned int>(10+g) );
+
+
+ sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0]
+ // verify the match with sbuffer
+ for (unsigned int i = 0; i < match_length; ++i)
+ {
+ DLIB_TEST(sbuffer[i+20-match_length] == sbuffer[i+1+match_index+20-match_length]);
+ }
+ sbuffer.rotate_left(1); // free up sbuffer[0] for new data
+
+ } // for (int g = 0; g < 8; ++g)
+
+
+
+
+
+
+
+ srand(static_cast<unsigned int>(time(0)));
+
+ for (int g = 0; g < 200; ++g)
+ {
+ test.clear();
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_limit() == 256-20);
+ DLIB_TEST(test.get_lookahead_buffer_limit() == 20);
+
+
+ sbuf sbuffer;
+ sbuffer.set_size(8);
+
+ ostringstream sout;
+ int l = ::rand()%500;
+ for (int i = 0; i < l; ++i)
+ {
+ char temp = static_cast<char>(::rand()%256);
+ sout << temp;
+ }
+ istringstream sin(sout.str());
+
+ unsigned char ch;
+ for (int i = 0; i < l; ++i)
+ {
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ }
+
+ // make sure the contents of lookahead_buffer and history_buffer
+ // match what is in sbuffer
+ sbuffer.rotate_right(1);
+
+ // adjust so that sbuffer[19] is the same as lookahead_buffer[0]
+ if (test.get_lookahead_buffer_size() < 20)
+ sbuffer.rotate_left(20-test.get_lookahead_buffer_size());
+
+ for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i));
+ }
+ for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i));
+ }
+ sbuffer.rotate_left(1);
+
+
+
+ unsigned long match_index, match_length;
+ unsigned long lookahead_size_before = test.get_lookahead_buffer_size();
+ test.find_match(match_index,match_length,0);
+ DLIB_TEST(match_length <= lookahead_size_before);
+
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == lookahead_size_before-match_length);
+
+ sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0]
+ // verify the match with sbuffer
+ for (unsigned int i = 0; i < match_length; ++i)
+ {
+ DLIB_TEST_MSG(sbuffer[19-i] == sbuffer[match_index+20-i],i);
+ }
+ sbuffer.rotate_left(1); // free up sbuffer[0] for new data
+
+ } // for (int g = 0; g < 200; ++g)
+
+
+
+
+
+
+
+
+ srand(static_cast<unsigned int>(time(0)));
+
+ for (int g = 0; g < 300; ++g)
+ {
+ test.clear();
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_size() == 0);
+ DLIB_TEST(test.get_history_buffer_limit() == 256-20);
+ DLIB_TEST(test.get_lookahead_buffer_limit() == 20);
+
+
+ sbuf sbuffer;
+ sbuffer.set_size(8);
+
+ ostringstream sout;
+ int l = ::rand()%500;
+ for (int i = 0; i < l; ++i)
+ {
+ char temp = static_cast<char>(::rand()%20);
+ sout << temp;
+ sout << temp;
+ sout << temp;
+ sout << temp;
+ sout << temp;
+ sout << temp;
+ }
+ istringstream sin(sout.str());
+
+ unsigned char ch;
+ for (int i = 0; i < l; ++i)
+ {
+ ch = sin.get();
+ sbuffer[0] = ch; sbuffer.rotate_left(1);
+ test.add(ch);
+ }
+
+ // make sure the contents of lookahead_buffer and history_buffer
+ // match what is in sbuffer
+ sbuffer.rotate_right(1);
+
+ // adjust so that sbuffer[19] is the same as lookahead_buffer[0]
+ if (test.get_lookahead_buffer_size() < 20)
+ sbuffer.rotate_left(20-test.get_lookahead_buffer_size());
+
+ for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i));
+ }
+ for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i)
+ {
+ DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i));
+ }
+ sbuffer.rotate_left(1);
+
+
+
+ unsigned long match_index = 0, match_length = 0;
+ unsigned long lookahead_size_before = test.get_lookahead_buffer_size();
+ unsigned long history_size_before = test.get_history_buffer_size();
+ test.find_match(match_index,match_length,2);
+
+ if (match_length != 0)
+ {
+ DLIB_TEST_MSG(match_index < history_size_before,
+ "match_index: " << match_index <<
+ "\nhistory_size_before: " << history_size_before);
+
+ }
+
+
+ DLIB_TEST(test.get_lookahead_buffer_size() == lookahead_size_before-match_length);
+
+ sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0]
+ // verify the match with sbuffer
+ for (unsigned int i = 0; i < match_length; ++i)
+ {
+ DLIB_TEST_MSG(sbuffer[19-i] == sbuffer[match_index+20-i],i);
+ }
+ sbuffer.rotate_left(1); // free up sbuffer[0] for new data
+
+
+
+ } // for (int g = 0; g < 300; ++g)
+
+ }
+
+
+
+
+ class lz77_buffer_tester : public tester
+ {
+ public:
+ lz77_buffer_tester (
+ ) :
+ tester ("test_lz77_buffer",
+ "Runs tests on the lz77_buffer component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ lz77_buffer_kernel_test<lz77_buffer::kernel_1a> ();
+ dlog << LINFO << "testing kernel_1a_c";
+ lz77_buffer_kernel_test<lz77_buffer::kernel_1a_c>();
+ dlog << LINFO << "testing kernel_2a";
+ lz77_buffer_kernel_test<lz77_buffer::kernel_2a> ();
+ dlog << LINFO << "testing kernel_2a_c";
+ lz77_buffer_kernel_test<lz77_buffer::kernel_2a_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/main.cpp b/ml/dlib/dlib/test/main.cpp
new file mode 100644
index 000000000..4800a7211
--- /dev/null
+++ b/ml/dlib/dlib/test/main.cpp
@@ -0,0 +1,217 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <iostream>
+#include <fstream>
+#include <dlib/cmd_line_parser.h>
+#include "tester.h"
+#include <dlib/string.h>
+
+
+using namespace std;
+using namespace dlib;
+using namespace test;
+
+typedef cmd_line_parser<char>::check_1a_c clp;
+
+static logger dlog("test.main");
+
+int main (int argc, char** argv)
+{
+ try
+ {
+ clp parser;
+
+ parser.add_option("runall","Run all the tests that don't take any arguments.");
+ parser.add_option("h","Displays this information.");
+ parser.add_option("n","How many times to run the selected tests. The default is 1.",1);
+ parser.add_option("d","log debugging statements to file debug.txt.");
+ parser.add_option("l","Set the logging level (all, trace, debug, info, warn, error, or fatal), the default is all.",1);
+ parser.add_option("a","Append debugging messages to debug.txt rather than clearing the file at program startup.");
+ parser.add_option("q","Be quiet. Don't print the testing progress or results to standard out.");
+
+ unsigned long num = 1;
+
+ // add the options for all the different tests
+ testers().reset();
+ while (testers().move_next())
+ {
+ tester& test = *testers().element().value();
+ parser.add_option(test.cmd_line_switch(), test.description(), test.num_of_args());
+ }
+
+ parser.parse(argc,argv);
+
+ parser.check_option_arg_range("n",1,1000000000);
+ const char* singles[] = {"d","l","a","n","h","runall","q"};
+ parser.check_one_time_options(singles);
+ const char* d_sub[] = {"l","a"};
+ const char* l_args[] = {"all", "trace", "debug", "info", "warn", "error", "fatal"};
+ parser.check_sub_options("d",d_sub);
+ parser.check_option_arg_range("l",l_args);
+
+
+ if (parser.option("n"))
+ {
+ num = string_cast<unsigned long>(parser.option("n").argument());
+ }
+
+ if (parser.option("q"))
+ {
+ be_verbose = false;
+ }
+
+ if (parser.option("h"))
+ {
+ cout << "Usage: test [options]\n";
+ parser.print_options(cout);
+ cout << "\n\n";
+ return 0;
+ }
+
+ ofstream fout;
+ if (parser.option("d"))
+ {
+ if (parser.option("a"))
+ fout.open("debug.txt",ios::app);
+ else
+ fout.open("debug.txt");
+
+ set_all_logging_output_streams(fout);
+
+ if (parser.option("l").count() == 0)
+ set_all_logging_levels(LALL);
+ else if (parser.option("l").argument() == "all")
+ set_all_logging_levels(LALL);
+ else if (parser.option("l").argument() == "trace")
+ set_all_logging_levels(LTRACE);
+ else if (parser.option("l").argument() == "debug")
+ set_all_logging_levels(LDEBUG);
+ else if (parser.option("l").argument() == "info")
+ set_all_logging_levels(LINFO);
+ else if (parser.option("l").argument() == "warn")
+ set_all_logging_levels(LWARN);
+ else if (parser.option("l").argument() == "error")
+ set_all_logging_levels(LERROR);
+ else if (parser.option("l").argument() == "fatal")
+ set_all_logging_levels(LFATAL);
+ }
+ else
+ {
+ set_all_logging_levels(LNONE);
+ }
+
+ unsigned long num_of_failed_tests = 0;
+ unsigned long num_of_passed_tests = 0;
+ for (unsigned long i = 0; i < num; ++i)
+ {
+ dlog << LINFO << "************ Starting Test Run " << i+1 << " of " << num << ". ************";
+
+ // loop over all the testers and see if they are supposed to run
+ testers().reset();
+ while (testers().move_next())
+ {
+ tester& test= *testers().element().value();
+ const clp::option_type& opt = parser.option(test.cmd_line_switch());
+ // run the test for this option as many times as the user has requested.
+ for (unsigned long j = 0; j < parser.option("runall").count() + opt.count(); ++j)
+ {
+ // quit this loop if this option has arguments and this round through the loop is
+ // from the runall option being present.
+ if (test.num_of_args() > 0 && j == opt.count())
+ break;
+
+ if (be_verbose)
+ cout << "Running " << test.cmd_line_switch() << " " << flush;
+
+ dlog << LINFO << "Running " << test.cmd_line_switch();
+ try
+ {
+ switch (test.num_of_args())
+ {
+ case 0:
+ test.perform_test();
+ break;
+ case 1:
+ test.perform_test(opt.argument(0,j));
+ break;
+ case 2:
+ test.perform_test(opt.argument(0,j), opt.argument(1,j));
+ break;
+ default:
+ cerr << "\n\nThe test '" << test.cmd_line_switch() << "' requested " << test.num_of_args()
+ << " arguments but only 2 are supported." << endl;
+ dlog << LINFO << "The test '" << test.cmd_line_switch() << "' requested " << test.num_of_args()
+ << " arguments but only 2 are supported.";
+ break;
+ }
+ if (be_verbose)
+ cout << "\r \r";
+
+ ++num_of_passed_tests;
+
+ }
+ catch (std::exception& e)
+ {
+ if (be_verbose)
+ {
+ cout << "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
+ cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TEST FAILED: " << test.cmd_line_switch()
+ << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
+ cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n";
+ cout << "Failure message from test: " << e.what() << endl;
+ }
+
+
+ dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
+ dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TEST FAILED: " << test.cmd_line_switch()
+ << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
+ dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
+ dlog << LERROR << "Failure message from test: " << e.what();
+ ++num_of_failed_tests;
+ }
+ }
+ }
+ }
+ dlog << LINFO << "Testing Finished";
+ if (num_of_passed_tests == 0 && num_of_failed_tests == 0)
+ {
+ cout << "You didn't select any tests to run.\n";
+ cout << "Try the -h option for more information.\n";
+ }
+ else if (num_of_failed_tests == 0)
+ {
+ if (be_verbose)
+ {
+ cout << "\n\nTesting Finished\n";
+ cout << "Total number of individual testing statements executed: "<< number_of_testing_statements_executed() << endl;
+ cout << "All tests completed successfully\n\n";
+ }
+ dlog << LINFO << "Total number of individual testing statements executed: "<< number_of_testing_statements_executed();
+ dlog << LINFO << "All tests completed successfully";
+ }
+ else
+ {
+ if (be_verbose)
+ {
+ cout << "\n\nTesting Finished\n";
+ cout << "Total number of individual testing statements executed: "<< number_of_testing_statements_executed() << endl;
+ cout << "Number of failed tests: " << num_of_failed_tests << "\n";
+ cout << "Number of passed tests: " << num_of_passed_tests << "\n\n";
+ }
+ dlog << LINFO << "Total number of individual testing statements executed: "<< number_of_testing_statements_executed();
+ dlog << LWARN << "Number of failed tests: " << num_of_failed_tests;
+ dlog << LWARN << "Number of passed tests: " << num_of_passed_tests;
+ }
+
+ return num_of_failed_tests;
+ }
+ catch (exception& e)
+ {
+ cout << e.what() << endl;
+ cout << "\nTry the -h option for more information.\n";
+ cout << endl;
+ }
+}
+
diff --git a/ml/dlib/dlib/test/makefile b/ml/dlib/dlib/test/makefile
new file mode 100644
index 000000000..d4d478705
--- /dev/null
+++ b/ml/dlib/dlib/test/makefile
@@ -0,0 +1,185 @@
+# This is the makefile used to build the dlib C++ library's regression test suite
+# on Debian Linux using the gcc compiler.
+
+# this is the name of the output executable
+TARGET = dtest
+
+# these are the compile time flags passed to gcc
+CXXFLAGS ?= -ggdb -Wall
+CPPFLAGS ?= -std=c++11 -DDEBUG -DDLIB_NO_GUI_SUPPORT -I../..
+
+# These are the link time flags passed to gcc
+LFLAGS = -lpthread -lnsl
+
+# The name of the compiler. If you only have one version of
+# gcc installed then you probably want to change this to just g++
+CXX ?= nice g++
+
+####################################################
+####################################################
+# Here we list all the cpp files we want to compile
+
+SRC = main.cpp
+SRC += tester.cpp
+SRC += ../all/source.cpp
+
+SRC += example.cpp
+SRC += example_args.cpp
+
+SRC += active_learning.cpp
+SRC += any.cpp
+SRC += any_function.cpp
+SRC += array2d.cpp
+SRC += array.cpp
+SRC += assignment_learning.cpp
+SRC += base64.cpp
+SRC += bayes_nets.cpp
+SRC += bigint.cpp
+SRC += binary_search_tree_kernel_1a.cpp
+SRC += binary_search_tree_kernel_2a.cpp
+SRC += binary_search_tree_mm1.cpp
+SRC += binary_search_tree_mm2.cpp
+SRC += bridge.cpp
+SRC += bsp.cpp
+SRC += byte_orderer.cpp
+SRC += cca.cpp
+SRC += clustering.cpp
+SRC += cmd_line_parser.cpp
+SRC += cmd_line_parser_wchar_t.cpp
+SRC += compress_stream.cpp
+SRC += conditioning_class_c.cpp
+SRC += conditioning_class.cpp
+SRC += config_reader.cpp
+SRC += crc32.cpp
+SRC += create_iris_datafile.cpp
+SRC += data_io.cpp
+SRC += directed_graph.cpp
+SRC += discriminant_pca.cpp
+SRC += disjoint_subsets.cpp
+SRC += ekm_and_lisf.cpp
+SRC += empirical_kernel_map.cpp
+SRC += entropy_coder.cpp
+SRC += entropy_encoder_model.cpp
+SRC += face.cpp
+SRC += fft.cpp
+SRC += fhog.cpp
+SRC += filtering.cpp
+SRC += find_max_factor_graph_nmplp.cpp
+SRC += find_max_factor_graph_viterbi.cpp
+SRC += geometry.cpp
+SRC += graph.cpp
+SRC += graph_cuts.cpp
+SRC += graph_labeler.cpp
+SRC += hash.cpp
+SRC += hash_map.cpp
+SRC += hash_set.cpp
+SRC += hash_table.cpp
+SRC += hog_image.cpp
+SRC += image.cpp
+SRC += iosockstream.cpp
+SRC += is_same_object.cpp
+SRC += kcentroid.cpp
+SRC += kernel_matrix.cpp
+SRC += kmeans.cpp
+SRC += learning_to_track.cpp
+SRC += least_squares.cpp
+SRC += linear_manifold_regularizer.cpp
+SRC += lspi.cpp
+SRC += lz77_buffer.cpp
+SRC += map.cpp
+SRC += matrix2.cpp
+SRC += matrix3.cpp
+SRC += matrix4.cpp
+SRC += matrix_chol.cpp
+SRC += matrix.cpp
+SRC += matrix_eig.cpp
+SRC += matrix_lu.cpp
+SRC += matrix_qr.cpp
+SRC += max_cost_assignment.cpp
+SRC += max_sum_submatrix.cpp
+SRC += md5.cpp
+SRC += member_function_pointer.cpp
+SRC += metaprogramming.cpp
+SRC += mpc.cpp
+SRC += multithreaded_object.cpp
+SRC += numerical_integration.cpp
+SRC += object_detector.cpp
+SRC += oca.cpp
+SRC += one_vs_all_trainer.cpp
+SRC += one_vs_one_trainer.cpp
+SRC += optimization.cpp
+SRC += optimization_test_functions.cpp
+SRC += opt_qp_solver.cpp
+SRC += parallel_for.cpp
+SRC += parse.cpp
+SRC += pipe.cpp
+SRC += pixel.cpp
+SRC += probabilistic.cpp
+SRC += pyramid_down.cpp
+SRC += queue.cpp
+SRC += rand.cpp
+SRC += ranking.cpp
+SRC += read_write_mutex.cpp
+SRC += reference_counter.cpp
+SRC += rls.cpp
+SRC += sammon.cpp
+SRC += scan_image.cpp
+SRC += sequence.cpp
+SRC += sequence_labeler.cpp
+SRC += sequence_segmenter.cpp
+SRC += serialize.cpp
+SRC += set.cpp
+SRC += sldf.cpp
+SRC += sliding_buffer.cpp
+SRC += sockets2.cpp
+SRC += sockets.cpp
+SRC += sockstreambuf.cpp
+SRC += sparse_vector.cpp
+SRC += stack.cpp
+SRC += static_map.cpp
+SRC += static_set.cpp
+SRC += statistics.cpp
+SRC += std_vector_c.cpp
+SRC += string.cpp
+SRC += svm_c_linear.cpp
+SRC += svm_c_linear_dcd.cpp
+SRC += svm.cpp
+SRC += svm_multiclass_linear.cpp
+SRC += svm_struct.cpp
+SRC += svr_linear_trainer.cpp
+SRC += symmetric_matrix_cache.cpp
+SRC += thread_pool.cpp
+SRC += threads.cpp
+SRC += timer.cpp
+SRC += tokenizer.cpp
+SRC += trust_region.cpp
+SRC += tuple.cpp
+SRC += type_safe_union.cpp
+SRC += vectorstream.cpp
+
+
+####################################################
+
+TMP = $(SRC:.cpp=.o)
+OBJ = $(TMP:.c=.o)
+
+$(TARGET): $(OBJ)
+ @echo Linking $@
+ @$(CXX) $(LDFLAGS) $(OBJ) $(LFLAGS) -o $@
+ @echo Build Complete
+
+clean:
+ @rm -f $(OBJ) $(TARGET)
+ @echo All object files and binaries removed
+
+dep:
+ @echo Running makedepend
+ @makedepend -- $(CFLAGS) -- $(SRC) 2> /dev/null
+ @echo Completed makedepend
+
+###############################################################################
+########## Stuff from makedepend #####
+########## type make dep at the command line to rebuild the dependencies #####
+########## Also, DON'T edit the contents of this file beyond this line. #####
+###############################################################################
+
diff --git a/ml/dlib/dlib/test/map.cpp b/ml/dlib/dlib/test/map.cpp
new file mode 100644
index 000000000..6901ddf05
--- /dev/null
+++ b/ml/dlib/dlib/test/map.cpp
@@ -0,0 +1,441 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/map.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.map");
+
+ template <
+ typename map
+ >
+ void map_kernel_test (
+ )
+ /*!
+ requires
+ - map is an implementation of map/map_kernel_abstract.h and
+ is instantiated to map int to int
+ ensures
+ - runs tests on map for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ srand(static_cast<unsigned int>(time(0)));
+
+
+
+ map test, test2;
+
+ enumerable<map_pair<int,int> >& e = test;
+ DLIB_TEST(e.at_start() == true);
+
+ for (int j = 0; j < 4; ++j)
+ {
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+
+
+ int a,b;
+ a = 8;
+ b = 94;
+ test.add(a,b);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(test.is_in_domain(8) == true);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+ DLIB_TEST(test[8] == 94);
+ a = 53;
+ b = 4;
+ test.add(a,b);
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test.is_in_domain(53) == true);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+ DLIB_TEST(test[53] == 4);
+
+
+ swap(test,test2);
+
+
+ DLIB_TEST(test2.size() == 2);
+ DLIB_TEST(test2.is_in_domain(8) == true);
+ DLIB_TEST(test2.is_in_domain(5) == false);
+ DLIB_TEST(test2.is_in_domain(0) == false);
+ DLIB_TEST(test2.is_in_domain(-999) == false);
+ DLIB_TEST(test2.is_in_domain(4999) == false);
+ DLIB_TEST(test2[8] == 94);
+ DLIB_TEST(test2.size() == 2);
+ DLIB_TEST(test2.is_in_domain(53) == true);
+ DLIB_TEST(test2.is_in_domain(5) == false);
+ DLIB_TEST(test2.is_in_domain(0) == false);
+ DLIB_TEST(test2.is_in_domain(-999) == false);
+ DLIB_TEST(test2.is_in_domain(4999) == false);
+ DLIB_TEST(test2[53] == 4);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_in_domain(8) == false);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_in_domain(53) == false);
+ DLIB_TEST(test.is_in_domain(5) == false);
+ DLIB_TEST(test.is_in_domain(0) == false);
+ DLIB_TEST(test.is_in_domain(-999) == false);
+ DLIB_TEST(test.is_in_domain(4999) == false);
+
+
+ test.clear();
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+ test.clear();
+ DLIB_TEST(test.size() == 0);
+
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+
+ int count = 0;
+ a = -1;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element().key() == test.element().key());
+ DLIB_TEST(test.element().value() == test.element().value());
+ DLIB_TEST(test.element().key() == test.element().key());
+ DLIB_TEST(test.element().value() == test.element().value());
+
+
+ DLIB_TEST(a < test.element().key());
+ a = test.element().key();
+ ++count;
+ }
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+
+ DLIB_TEST(count == 10000);
+
+ test.swap(test2);
+
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test2.size() == 10000);
+ count = 0;
+ a = -1;
+ test2.reset();
+
+ test2.move_next();
+ test2.element().value() = 99;
+ DLIB_TEST(test2[test2.element().key()] == 99);
+ DLIB_TEST(test2.element().value() == 99);
+
+ test2.reset();
+
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2[test2.element().key()] == test2.element().value());
+ DLIB_TEST(test2.element().key() == test2.element().key());
+ DLIB_TEST(test2.element().value() == test2.element().value());
+ DLIB_TEST(test2.element().key() == test2.element().key());
+ DLIB_TEST(test2.element().value() == test2.element().value());
+ DLIB_TEST(a < test2.element().key());
+ a = test2.element().key();
+ ++count;
+ }
+ DLIB_TEST(test2.size() == 10000);
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.move_next() == false);
+
+
+
+ test2.clear();
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.at_start() == true);
+
+ while (test.size() < 20000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ // serialize the state of test, then clear test, then
+ // load the state back into test.
+ ostringstream sout;
+ serialize(test,sout);
+ istringstream sin(sout.str());
+ test.clear();
+ deserialize(test,sin);
+
+ DLIB_TEST(test.at_start() == true);
+
+ {
+ int* array1 = new int[test.size()];
+ int* array2 = new int[test.size()];
+
+ int* tmp1 = array1;
+ int* tmp2 = array2;
+
+ count = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element().key() == test.element().key());
+ DLIB_TEST(test.element().value() == test.element().value());
+ DLIB_TEST(test.element().key() == test.element().key());
+ DLIB_TEST(test.current_element_valid() == true);
+ *tmp1 = test.element().key();
+ *tmp2 = test.element().value();
+ ++tmp1;
+ ++tmp2;
+ ++count;
+ }
+ DLIB_TEST(count == 20000);
+
+ tmp1 = array1;
+ tmp2 = array2;
+ for (int i = 0; i < 20000; ++i)
+ {
+ DLIB_TEST(test.is_in_domain(*tmp1) == true);
+ DLIB_TEST(test[*tmp1] == *tmp2);
+ ++tmp1;
+ ++tmp2;
+ }
+
+ DLIB_TEST(test.size() == 20000);
+
+ tmp1 = array1;
+ tmp2 = array2;
+ count = 0;
+ while (test.size() > 10000)
+ {
+ test.remove(*tmp1,a,b);
+ DLIB_TEST(*tmp1 == a);
+ DLIB_TEST(*tmp2 == b);
+ ++tmp1;
+ ++tmp2;
+ ++count;
+ }
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test.size() == 10000);
+
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element().key() == *tmp1);
+ DLIB_TEST(test.element().key() == *tmp1);
+ DLIB_TEST(test.element().key() == *tmp1);
+ DLIB_TEST(test.element().value() == *tmp2);
+ DLIB_TEST(test.element().value() == *tmp2);
+ DLIB_TEST(test.element().value() == *tmp2);
+ ++tmp1;
+ ++tmp2;
+ ++count;
+ }
+ DLIB_TEST(count == 20000);
+ DLIB_TEST(test.size() == 10000);
+
+ while (test.size() < 20000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ test2.swap(test);
+
+ count = 0;
+ a = -1;
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2.element().key() == test2.element().key());
+ DLIB_TEST(test2.element().value() == test2.element().value());
+ DLIB_TEST(test2.element().key() == test2.element().key());
+ DLIB_TEST(a < test2.element().key());
+ a = test2.element().key();
+ ++count;
+ }
+
+ DLIB_TEST(count == 20000);
+ DLIB_TEST(test2.size() == 20000);
+
+ a = -1;
+ int c = 0;
+ while (test2.size()>0)
+ {
+ test2.remove_any(b,c);
+ DLIB_TEST( a < b);
+ a = b;
+ }
+
+ DLIB_TEST(test2.size() == 0);
+ delete [] array1;
+ delete [] array2;
+ }
+
+ test.clear();
+ test2.clear();
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ b = ::rand();
+ if (!test.is_in_domain(a))
+ test.add(a,b);
+ }
+
+ count = 0;
+ a = -1;
+ while (test.move_next())
+ {
+ DLIB_TEST(a < test.element().key());
+ DLIB_TEST(test[test.element().key()] == test.element().value());
+ a = test.element().key();
+ ++count;
+ if (count == 5000)
+ break;
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ test.reset();
+
+ count = 0;
+ a = -1;
+ while (test.move_next())
+ {
+ DLIB_TEST(a < test.element().key());
+ a = test.element().key();
+ ++count;
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ DLIB_TEST(count == 10000);
+
+
+ test.clear();
+ test2.clear();
+ }
+
+
+ {
+ test.clear();
+ DLIB_TEST(test.size() == 0);
+ int a = 5;
+ int b = 6;
+ test.add(a,b);
+ a = 7;
+ b = 8;
+ test.add(a,b);
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test[7] == 8);
+ DLIB_TEST(test[5] == 6);
+ DLIB_TEST(test.is_in_domain(7));
+ DLIB_TEST(test.is_in_domain(5));
+ test.destroy(7);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(!test.is_in_domain(7));
+ DLIB_TEST(test.is_in_domain(5));
+ test.destroy(5);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(!test.is_in_domain(7));
+ DLIB_TEST(!test.is_in_domain(5));
+ }
+
+ }
+
+
+
+
+ class map_tester : public tester
+ {
+ public:
+ map_tester (
+ ) :
+ tester ("test_map",
+ "Runs tests on the map component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ map_kernel_test<dlib::map<int,int>::kernel_1a> ();
+ dlog << LINFO << "testing kernel_1a_c";
+ map_kernel_test<dlib::map<int,int>::kernel_1a_c>();
+ dlog << LINFO << "testing kernel_1b";
+ map_kernel_test<dlib::map<int,int>::kernel_1b> ();
+ dlog << LINFO << "testing kernel_1b_c";
+ map_kernel_test<dlib::map<int,int>::kernel_1b_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/matrix.cpp b/ml/dlib/dlib/test/matrix.cpp
new file mode 100644
index 000000000..0a3ea5996
--- /dev/null
+++ b/ml/dlib/dlib/test/matrix.cpp
@@ -0,0 +1,1519 @@
+
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+
+#include "tester.h"
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/array2d.h>
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ dlib::rand rnd;
+
+ logger dlog("test.matrix");
+
+ template <typename type>
+ const matrix<type> rand_sp_banded(long n, long bw)
+ {
+ matrix<type> m = 10 * identity_matrix<type>(n);
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = row; col < min(m.nc(), row + bw); ++col)
+ {
+ type r = rnd.get_random_double();
+ m(row,col) += r;
+ m(col,row) += r;
+ }
+ }
+
+ return m;
+ }
+
+ void matrix_test (
+ )
+ /*!
+ ensures
+ - runs tests on the matrix stuff compliance with the specs
+ !*/
+ {
+ typedef memory_manager_stateless<char>::kernel_2_2a MM;
+ print_spinner();
+
+
+ {
+ matrix<complex<double>,2,2,MM> m;
+ set_all_elements(m,complex<double>(1,2));
+ DLIB_TEST((conj(m) == uniform_matrix<complex<double>,2,2>(conj(m(0,0)))));
+ DLIB_TEST((real(m) == uniform_matrix<double,2,2>(1)));
+ DLIB_TEST((imag(m) == uniform_matrix<double,2,2>(2)));
+ DLIB_TEST_MSG((sum(abs(norm(m) - uniform_matrix<double,2,2>(5))) < 1e-10 ),norm(m));
+
+ }
+
+ {
+ matrix<double,5,5,MM,column_major_layout> m(5,5);
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ m = cos(exp(m));
+
+
+ matrix<double> mi = pinv(m );
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m))));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m))));
+
+ mi = pinv(m,1e-12);
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m))));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m))));
+
+ m = diagm(diag(m));
+ mi = pinv(diagm(diag(m)),1e-12);
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m))));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m))));
+
+ mi = pinv(m,0);
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m))));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m))));
+
+ m = diagm(diag(m));
+ mi = pinv(diagm(diag(m)),0);
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m))));
+ DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m))));
+ }
+ {
+ matrix<double,5,0,MM> m(5,5);
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ m = cos(exp(m));
+
+
+ matrix<double> mi = pinv(m );
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())));
+ }
+
+ {
+ matrix<double,0,5,MM> m(5,5);
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ m = cos(exp(m));
+
+
+ matrix<double> mi = pinv(m );
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())));
+ }
+
+
+ {
+ matrix<double> m(5,5);
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ m = cos(exp(m));
+
+
+ matrix<double> mi = pinv(m );
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())));
+ }
+
+ {
+ matrix<double,5,2,MM,column_major_layout> m;
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ m = cos(exp(m));
+
+
+ matrix<double> mi = pinv(m );
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,2>())));
+ }
+
+ {
+ matrix<double> m(5,2);
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ m = cos(exp(m));
+
+
+ matrix<double> mi = pinv(m );
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,2>())));
+ }
+
+ {
+ matrix<double,5,2,MM,column_major_layout> m;
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ m = cos(exp(m));
+
+
+ matrix<double> mi = trans(pinv(trans(m) ));
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,2>())));
+ }
+
+ {
+ matrix<double> m(5,2);
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ m = cos(exp(m));
+
+
+ matrix<double> mi = trans(pinv(trans(m) ));
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,2>())));
+ }
+
+ {
+ matrix<long> a1(5,1);
+ matrix<long,0,0,MM,column_major_layout> a2(1,5);
+ matrix<long,5,1> b1(5,1);
+ matrix<long,1,5> b2(1,5);
+ matrix<long,0,1> c1(5,1);
+ matrix<long,1,0> c2(1,5);
+ matrix<long,0,1,MM,column_major_layout> d1(5,1);
+ matrix<long,1,0,MM> d2(1,5);
+
+ for (long i = 0; i < 5; ++i)
+ {
+ a1(i) = i;
+ a2(i) = i;
+ b1(i) = i;
+ b2(i) = i;
+ c1(i) = i;
+ c2(i) = i;
+ d1(i) = i;
+ d2(i) = i;
+ }
+
+ DLIB_TEST(a1 == trans(a2));
+ DLIB_TEST(a1 == trans(b2));
+ DLIB_TEST(a1 == trans(c2));
+ DLIB_TEST(a1 == trans(d2));
+
+ DLIB_TEST(a1 == b1);
+ DLIB_TEST(a1 == c1);
+ DLIB_TEST(a1 == d1);
+
+ DLIB_TEST(trans(a1) == c2);
+ DLIB_TEST(trans(b1) == c2);
+ DLIB_TEST(trans(c1) == c2);
+ DLIB_TEST(trans(d1) == c2);
+
+ DLIB_TEST(sum(a1) == 10);
+ DLIB_TEST(sum(a2) == 10);
+ DLIB_TEST(sum(b1) == 10);
+ DLIB_TEST(sum(b2) == 10);
+ DLIB_TEST(sum(c1) == 10);
+ DLIB_TEST(sum(c2) == 10);
+ DLIB_TEST(sum(d1) == 10);
+ DLIB_TEST(sum(d2) == 10);
+
+ const matrix<long> orig1 = a1;
+ const matrix<long> orig2 = a2;
+
+ ostringstream sout;
+ serialize(a1,sout);
+ serialize(a2,sout);
+ serialize(b1,sout);
+ serialize(b2,sout);
+ serialize(c1,sout);
+ serialize(c2,sout);
+ serialize(d1,sout);
+ serialize(d2,sout);
+
+ DLIB_TEST(a1 == orig1);
+ DLIB_TEST(a2 == orig2);
+ DLIB_TEST(b1 == orig1);
+ DLIB_TEST(b2 == orig2);
+ DLIB_TEST(c1 == orig1);
+ DLIB_TEST(c2 == orig2);
+ DLIB_TEST(d1 == orig1);
+ DLIB_TEST(d2 == orig2);
+
+ set_all_elements(a1,99);
+ set_all_elements(a2,99);
+ set_all_elements(b1,99);
+ set_all_elements(b2,99);
+ set_all_elements(c1,99);
+ set_all_elements(c2,99);
+ set_all_elements(d1,99);
+ set_all_elements(d2,99);
+
+ DLIB_TEST(a1 != orig1);
+ DLIB_TEST(a2 != orig2);
+ DLIB_TEST(b1 != orig1);
+ DLIB_TEST(b2 != orig2);
+ DLIB_TEST(c1 != orig1);
+ DLIB_TEST(c2 != orig2);
+ DLIB_TEST(d1 != orig1);
+ DLIB_TEST(d2 != orig2);
+
+ istringstream sin(sout.str());
+
+ deserialize(a1,sin);
+ deserialize(a2,sin);
+ deserialize(b1,sin);
+ deserialize(b2,sin);
+ deserialize(c1,sin);
+ deserialize(c2,sin);
+ deserialize(d1,sin);
+ deserialize(d2,sin);
+
+ DLIB_TEST(a1 == orig1);
+ DLIB_TEST(a2 == orig2);
+ DLIB_TEST(b1 == orig1);
+ DLIB_TEST(b2 == orig2);
+ DLIB_TEST(c1 == orig1);
+ DLIB_TEST(c2 == orig2);
+ DLIB_TEST(d1 == orig1);
+ DLIB_TEST(d2 == orig2);
+
+
+ }
+
+ {
+ matrix<double,1,0> a(5);
+ matrix<double,0,1> b(5);
+ matrix<double,1,5> c(5);
+ matrix<double,5,1> d(5);
+ DLIB_TEST(a.nr() == 1);
+ DLIB_TEST(a.nc() == 5);
+ DLIB_TEST(c.nr() == 1);
+ DLIB_TEST(c.nc() == 5);
+
+ DLIB_TEST(b.nc() == 1);
+ DLIB_TEST(b.nr() == 5);
+ DLIB_TEST(d.nc() == 1);
+ DLIB_TEST(d.nr() == 5);
+ }
+
+ {
+ matrix<double,1,0> a;
+ matrix<double,0,1> b;
+ matrix<double,1,5> c;
+ matrix<double,5,1> d;
+
+ a.set_size(5);
+ b.set_size(5);
+ c.set_size(5);
+ d.set_size(5);
+
+ DLIB_TEST(a.nr() == 1);
+ DLIB_TEST(a.nc() == 5);
+ DLIB_TEST(c.nr() == 1);
+ DLIB_TEST(c.nc() == 5);
+
+ DLIB_TEST(b.nc() == 1);
+ DLIB_TEST(b.nr() == 5);
+ DLIB_TEST(d.nc() == 1);
+ DLIB_TEST(d.nr() == 5);
+ }
+
+ {
+ matrix<double> a(1,5);
+ matrix<double> b(5,1);
+
+ set_all_elements(a,1);
+ set_all_elements(b,1);
+
+
+ a = a*b;
+
+ DLIB_TEST(a(0) == 5);
+ }
+
+ {
+ matrix<double,0,0,MM,column_major_layout> a(6,7);
+
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = r*a.nc() + c;
+ }
+ }
+
+
+
+ DLIB_TEST(rowm(a,1).nr() == 1);
+ DLIB_TEST(rowm(a,1).nc() == a.nc());
+ DLIB_TEST(colm(a,1).nr() == a.nr());
+ DLIB_TEST(colm(a,1).nc() == 1);
+
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ DLIB_TEST( rowm(a,1)(c) == 1*a.nc() + c);
+ }
+
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ DLIB_TEST( colm(a,1)(r) == r*a.nc() + 1);
+ }
+
+ rectangle rect(2, 1, 3+2-1, 2+1-1);
+ DLIB_TEST(get_rect(a).contains(get_rect(a)));
+ DLIB_TEST(get_rect(a).contains(rect));
+ for (long r = 0; r < 2; ++r)
+ {
+ for (long c = 0; c < 3; ++c)
+ {
+ DLIB_TEST(subm(a,1,2,2,3)(r,c) == (r+1)*a.nc() + c+2);
+ DLIB_TEST(subm(a,1,2,2,3) == subm(a,rect));
+ DLIB_TEST(subm_clipped(a,1,2,2,3) == subm(a,rect));
+ DLIB_TEST(subm_clipped(a,1,2,2,3) == subm_clipped(a,rect));
+ }
+ }
+
+ DLIB_TEST(subm(a,rectangle()).nr() == 0);
+ DLIB_TEST(subm(a,rectangle()).nc() == 0);
+
+ }
+
+ {
+ array2d<double> a;
+ a.set_size(6,7);
+
+
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a[r][c] = r*a.nc() + c;
+ }
+ }
+
+
+
+ DLIB_TEST(rowm(mat(a),1).nr() == 1);
+ DLIB_TEST(rowm(mat(a),1).nc() == a.nc());
+ DLIB_TEST(colm(mat(a),1).nr() == a.nr());
+ DLIB_TEST(colm(mat(a),1).nc() == 1);
+
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ DLIB_TEST( rowm(mat(a),1)(c) == 1*a.nc() + c);
+ }
+
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ DLIB_TEST( colm(mat(a),1)(r) == r*a.nc() + 1);
+ }
+
+ for (long r = 0; r < 2; ++r)
+ {
+ for (long c = 0; c < 3; ++c)
+ {
+ DLIB_TEST(subm(mat(a),1,2,2,3)(r,c) == (r+1)*a.nc() + c+2);
+ }
+ }
+
+
+ }
+
+ {
+ array2d<double> m;
+ m.set_size(5,5);
+
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m[r][c] = r*c;
+ }
+ }
+
+
+ matrix<double> mi = pinv(cos(exp(mat(m))) );
+ DLIB_TEST(mi.nr() == m.nc());
+ DLIB_TEST(mi.nc() == m.nr());
+ DLIB_TEST((equal(round_zeros(mi*cos(exp(mat(m))),0.000001) , identity_matrix<double,5>())));
+ DLIB_TEST((equal(round_zeros(cos(exp(mat(m)))*mi,0.000001) , identity_matrix<double,5>())));
+ }
+
+ {
+ matrix<long,5,5,MM,column_major_layout> m1, res;
+ matrix<long,2,2> m2;
+
+ set_all_elements(m1,0);
+
+
+ long res_vals[] = {
+ 9, 9, 9, 9, 9,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 2,
+ 0, 0, 2, 2, 2,
+ 0, 0, 2, 2, 0
+ };
+
+ res = res_vals;
+
+ set_all_elements(m2, 1);
+ set_subm(m1, range(1,2), range(1,2)) = subm(m2,0,0,2,2);
+ set_all_elements(m2, 2);
+ set_subm(m1, 3,2,2,2) = m2;
+
+ set_colm(m1,4) = trans(rowm(m1,4));
+ set_rowm(m1,0) = 9;
+
+ DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res);
+
+ set_subm(m1,0,0,5,5) = m1*m1;
+ DLIB_TEST_MSG(m1 == res*res, "m1: \n" << m1 << "\nres*res: \n" << res*res);
+
+ m1 = res;
+ set_subm(m1,1,1,2,2) = subm(m1,0,0,2,2);
+
+ long res_vals2[] = {
+ 9, 9, 9, 9, 9,
+ 0, 9, 9, 0, 0,
+ 0, 0, 1, 0, 2,
+ 0, 0, 2, 2, 2,
+ 0, 0, 2, 2, 0
+ };
+
+ res = res_vals2;
+ DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res);
+
+
+ }
+
+ {
+ matrix<long,5,5> m1, res;
+ matrix<long,2,2> m2;
+
+ set_all_elements(m1,0);
+
+
+ long res_vals[] = {
+ 9, 9, 9, 9, 9,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 2,
+ 0, 0, 2, 2, 2,
+ 0, 0, 2, 2, 0
+ };
+
+ res = res_vals;
+
+ set_all_elements(m2, 1);
+ set_subm(m1, rectangle(1,1,2,2)) = subm(m2,0,0,2,2);
+ set_all_elements(m2, 2);
+ set_subm(m1, 3,2,2,2) = m2;
+
+ set_colm(m1,4) = trans(rowm(m1,4));
+ set_rowm(m1,0) = 9;
+
+ DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res);
+
+ set_subm(m1,0,0,5,5) = m1*m1;
+ DLIB_TEST_MSG(m1 == res*res, "m1: \n" << m1 << "\nres*res: \n" << res*res);
+
+ m1 = res;
+ set_subm(m1,1,1,2,2) = subm(m1,0,0,2,2);
+
+ long res_vals2[] = {
+ 9, 9, 9, 9, 9,
+ 0, 9, 9, 0, 0,
+ 0, 0, 1, 0, 2,
+ 0, 0, 2, 2, 2,
+ 0, 0, 2, 2, 0
+ };
+
+ res = res_vals2;
+ DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res);
+
+
+ }
+
+ {
+ matrix<long,5,5> m1, res;
+ matrix<long,2,2> m2;
+
+ set_all_elements(m1,0);
+
+
+ long res_vals[] = {
+ 9, 0, 3, 3, 0,
+ 9, 2, 2, 2, 0,
+ 9, 2, 2, 2, 0,
+ 4, 4, 4, 4, 4,
+ 9, 0, 3, 3, 0
+ };
+ long res_vals_c3[] = {
+ 9, 0, 3, 0,
+ 9, 2, 2, 0,
+ 9, 2, 2, 0,
+ 4, 4, 4, 4,
+ 9, 0, 3, 0
+ };
+ long res_vals_r2[] = {
+ 9, 0, 3, 3, 0,
+ 9, 2, 2, 2, 0,
+ 4, 4, 4, 4, 4,
+ 9, 0, 3, 3, 0
+ };
+
+ matrix<long> temp;
+
+ res = res_vals;
+
+ temp = matrix<long,4,5>(res_vals_r2);
+ DLIB_TEST(remove_row<2>(res) == temp);
+ DLIB_TEST(remove_row<2>(res)(3,3) == 3);
+ DLIB_TEST(remove_row<2>(res).nr() == 4);
+ DLIB_TEST(remove_row<2>(res).nc() == 5);
+ DLIB_TEST(remove_row(res,2) == temp);
+ DLIB_TEST(remove_row(res,2)(3,3) == 3);
+ DLIB_TEST(remove_row(res,2).nr() == 4);
+ DLIB_TEST(remove_row(res,2).nc() == 5);
+
+ temp = matrix<long,5,5>(res_vals);
+ temp = remove_row(res,2);
+ DLIB_TEST((temp == matrix<long,4,5>(res_vals_r2)));
+ temp = matrix<long,5,5>(res_vals);
+ temp = remove_col(res,3);
+ DLIB_TEST((temp == matrix<long,5,4>(res_vals_c3)));
+
+ matrix<long,3,1> vect;
+ set_all_elements(vect,1);
+ temp = identity_matrix<long>(3);
+ temp = temp*vect;
+ DLIB_TEST(temp == vect);
+
+ temp = matrix<long,5,4>(res_vals_c3);
+ DLIB_TEST(remove_col(res,3) == temp);
+ DLIB_TEST(remove_col(res,3)(2,3) == 0);
+ DLIB_TEST(remove_col(res,3).nr() == 5);
+ DLIB_TEST(remove_col(res,3).nc() == 4);
+
+ set_all_elements(m2, 1);
+ set_subm(m1, rectangle(1,1,3,2)) = 2;
+ set_all_elements(m2, 2);
+ set_subm(m1, 3,2,2,2) = 3;
+
+ set_colm(m1,0) = 9;
+ set_rowm(m1,0) = rowm(m1,4);
+ set_rowm(m1,3) = 4;
+
+ DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res);
+
+ }
+
+ }
+
+
+ void matrix_test2()
+ {
+ print_spinner();
+
+
+ {
+
+ const double stuff[] = {
+ 1, 2, 3,
+ 6, 3, 3,
+ 7, 3, 9};
+
+ matrix<double,3,3> m(stuff);
+
+ // make m be symmetric
+ m = m*trans(m);
+
+ matrix<double> L = chol(m);
+ DLIB_TEST(equal(L*trans(L), m));
+
+ DLIB_TEST_MSG(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "");
+ DLIB_TEST(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10), identity_matrix<double>(3), 1e-10));
+ DLIB_TEST(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix<double>(3),1e-10));
+
+ }
+
+ {
+
+ const double stuff[] = {
+ 1, 2, 3, 6, 3, 4,
+ 6, 3, 3, 1, 2, 3,
+ 7, 3, 9, 54.3, 5, 3,
+ -6, 3, -3, 1, 2, 3,
+ 1, 2, 3, 5, -3, 3,
+ 7, 3, -9, 54.3, 5, 3
+ };
+
+ matrix<double,6,6> m(stuff);
+
+ // make m be symmetric
+ m = m*trans(m);
+
+ matrix<double> L = chol(m);
+ DLIB_TEST_MSG(equal(L*trans(L), m, 1e-10), L*trans(L)-m);
+
+ DLIB_TEST_MSG(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "");
+ DLIB_TEST_MSG(equal(inv(m), trans(inv_lower_triangular(L))*inv_lower_triangular((L))), "");
+ DLIB_TEST_MSG(equal(inv(m), trans(inv_lower_triangular(L))*trans(inv_upper_triangular(trans(L)))), "");
+ DLIB_TEST_MSG(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10) , identity_matrix<double>(6), 1e-10),
+ round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10));
+ DLIB_TEST_MSG(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix<double>(6), 1e-10),
+ round_zeros(inv_lower_triangular((L))*(L),1e-10));
+
+ }
+
+ {
+ // Test band chol
+ matrix<double> m = rand_sp_banded<double>(10, 3);
+
+ matrix<double> L = chol(m);
+ DLIB_TEST_MSG(equal(L*trans(L), m, 1e-10), L*trans(L)-m);
+ DLIB_TEST_MSG(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "");
+ DLIB_TEST_MSG(equal(inv(m), trans(inv_lower_triangular(L))*inv_lower_triangular((L))), "");
+ DLIB_TEST_MSG(equal(inv(m), trans(inv_lower_triangular(L))*trans(inv_upper_triangular(trans(L)))), "");
+ }
+
+ {
+ // Test band chol in column major layout
+ matrix<double,10,10,default_memory_manager,column_major_layout> m(rand_sp_banded<double>(10, 3));
+
+ matrix<double> L = chol(m);
+ DLIB_TEST_MSG(equal(L*trans(L), m, 1e-10), L*trans(L)-m);
+ DLIB_TEST_MSG(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "");
+ DLIB_TEST_MSG(equal(inv(m), trans(inv_lower_triangular(L))*inv_lower_triangular((L))), "");
+ DLIB_TEST_MSG(equal(inv(m), trans(inv_lower_triangular(L))*trans(inv_upper_triangular(trans(L)))), "");
+ }
+
+ {
+ matrix<int> m(3,4), m2;
+ m = 1,2,3,4,
+ 4,5,6,6,
+ 6,1,8,0;
+ m2 = m;
+ DLIB_TEST(round(m) == m2);
+ DLIB_TEST(round_zeros(m) == m2);
+
+ m2 = 0,2,3,4,
+ 4,5,6,6,
+ 6,0,8,0;
+
+ DLIB_TEST(round_zeros(m,2) == m2);
+ }
+
+
+ {
+
+ matrix<double,6,6> m(identity_matrix<double>(6)*4.5);
+
+ matrix<double> L = chol(m);
+ DLIB_TEST_MSG(equal(L*trans(L), m, 1e-10), L*trans(L)-m);
+
+ DLIB_TEST_MSG(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "");
+ DLIB_TEST_MSG(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10) , identity_matrix<double>(6), 1e-10),
+ round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10));
+ DLIB_TEST_MSG(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix<double>(6), 1e-10),
+ round_zeros(inv_lower_triangular((L))*(L),1e-10));
+
+ }
+
+ {
+
+ matrix<double,6,6> m(identity_matrix<double>(6)*4.5);
+ m(1,4) = 2;
+
+ DLIB_TEST_MSG(dlib::equal(inv_upper_triangular(m), inv(m),1e-10), inv_upper_triangular(m)-inv(m));
+ DLIB_TEST_MSG(dlib::equal(inv_lower_triangular(trans(m)), inv(trans(m)),1e-10), inv_lower_triangular(trans(m))-inv(trans(m)));
+
+ }
+
+ {
+ matrix<double> a;
+ matrix<float> b;
+ matrix<int> i;
+ a.set_size(1000,10);
+ b.set_size(1000,10);
+ i.set_size(1000,10);
+ dlib::rand rnd;
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = rnd.get_random_double();
+ b(r,c) = rnd.get_random_float();
+ i(r,c) = r+c*r;
+ }
+ }
+
+ // make sure the multiply optimizations aren't messing things up
+ DLIB_TEST(trans(i)*i == tmp(trans(i)*i));
+ DLIB_TEST_MSG(equal(trans(a)*a , tmp(trans(a)*a), 1e-11),max(abs(trans(a)*a - tmp(trans(a)*a))));
+ DLIB_TEST_MSG(equal(trans(b)*b , tmp(trans(b)*b), 1e-3f),max(abs(trans(b)*b - tmp(trans(b)*b))));
+ }
+
+ {
+ matrix<int,4> i(4,1);
+ i(0) = 1;
+ i(1) = 2;
+ i(2) = 3;
+ i(3) = 4;
+ matrix<int,4,4> m;
+ set_all_elements(m,0);
+ m(0,0) = 1;
+ m(1,1) = 2;
+ m(2,2) = 3;
+ m(3,3) = 4;
+
+ DLIB_TEST(diagm(i) == m);
+ }
+
+ {
+ matrix<int,1,4> i;
+ i(0) = 1;
+ i(1) = 2;
+ i(2) = 3;
+ i(3) = 4;
+ matrix<int,4,4> m;
+ set_all_elements(m,0);
+ m(0,0) = 1;
+ m(1,1) = 2;
+ m(2,2) = 3;
+ m(3,3) = 4;
+
+ DLIB_TEST(diagm(i) == m);
+ }
+
+ {
+ matrix<int> i(4,1);
+ i(0) = 1;
+ i(1) = 2;
+ i(2) = 3;
+ i(3) = 4;
+ matrix<int> m(4,4);
+ set_all_elements(m,0);
+ m(0,0) = 1;
+ m(1,1) = 2;
+ m(2,2) = 3;
+ m(3,3) = 4;
+
+ DLIB_TEST(diagm(i) == m);
+ }
+
+ {
+ matrix<int> i(1,4);
+ i(0) = 1;
+ i(1) = 2;
+ i(2) = 3;
+ i(3) = 4;
+ matrix<int> m(4,4);
+ set_all_elements(m,0);
+ m(0,0) = 1;
+ m(1,1) = 2;
+ m(2,2) = 3;
+ m(3,3) = 4;
+
+ DLIB_TEST(diagm(i) == m);
+ }
+
+ {
+ DLIB_TEST(range(0,5).nc() == 6);
+ DLIB_TEST(range(1,5).nc() == 5);
+ DLIB_TEST(range(0,5).nr() == 1);
+ DLIB_TEST(range(1,5).nr() == 1);
+ DLIB_TEST(trans(range(0,5)).nr() == 6);
+ DLIB_TEST(trans(range(1,5)).nr() == 5);
+ DLIB_TEST(trans(range(0,5)).nc() == 1);
+ DLIB_TEST(trans(range(1,5)).nc() == 1);
+
+ DLIB_TEST(range(0,2,5).nc() == 3);
+ DLIB_TEST(range(1,2,5).nc() == 3);
+ DLIB_TEST(range(0,2,5).nr() == 1);
+ DLIB_TEST(range(1,2,5).nr() == 1);
+ DLIB_TEST(trans(range(0,2,5)).nr() == 3);
+ DLIB_TEST(trans(range(1,2,5)).nr() == 3);
+ DLIB_TEST(trans(range(0,2,5)).nc() == 1);
+ DLIB_TEST(trans(range(1,2,5)).nc() == 1);
+
+ DLIB_TEST(range(0,3,6).nc() == 3);
+ DLIB_TEST(range(1,3,5).nc() == 2);
+ DLIB_TEST(range(0,3,5).nr() == 1);
+ DLIB_TEST(range(1,3,5).nr() == 1);
+ DLIB_TEST(trans(range(0,3,6)).nr() == 3);
+ DLIB_TEST(trans(range(1,3,5)).nr() == 2);
+ DLIB_TEST(trans(range(0,3,5)).nc() == 1);
+ DLIB_TEST(trans(range(1,3,5)).nc() == 1);
+
+ DLIB_TEST(range(1,9,5).nc() == 1);
+ DLIB_TEST(range(1,9,5).nr() == 1);
+
+ DLIB_TEST(range(0,0).nc() == 1);
+ DLIB_TEST(range(0,0).nr() == 1);
+
+ DLIB_TEST(range(1,1)(0) == 1);
+
+ DLIB_TEST(range(0,5)(0) == 0 && range(0,5)(1) == 1 && range(0,5)(5) == 5);
+ DLIB_TEST(range(1,2,5)(0) == 1 && range(1,2,5)(1) == 3 && range(1,2,5)(2) == 5);
+ DLIB_TEST((range<0,5>()(0) == 0 && range<0,5>()(1) == 1 && range<0,5>()(5) == 5));
+ DLIB_TEST((range<1,2,5>()(0) == 1 && range<1,2,5>()(1) == 3 && range<1,2,5>()(2) == 5));
+
+
+ DLIB_TEST((range<0,5>().nc() == 6));
+ DLIB_TEST((range<1,5>().nc() == 5));
+ DLIB_TEST((range<0,5>().nr() == 1));
+ DLIB_TEST((range<1,5>().nr() == 1));
+ DLIB_TEST((trans(range<0,5>()).nr() == 6));
+ DLIB_TEST((trans(range<1,5>()).nr() == 5));
+ DLIB_TEST((trans(range<0,5>()).nc() == 1));
+ DLIB_TEST((trans(range<1,5>()).nc() == 1));
+
+ DLIB_TEST((range<0,2,5>().nc() == 3));
+ DLIB_TEST((range<1,2,5>().nc() == 3));
+ DLIB_TEST((range<0,2,5>().nr() == 1));
+ DLIB_TEST((range<1,2,5>().nr() == 1));
+ DLIB_TEST((trans(range<0,2,5>()).nr() == 3));
+ DLIB_TEST((trans(range<1,2,5>()).nr() == 3));
+ DLIB_TEST((trans(range<0,2,5>()).nc() == 1));
+ DLIB_TEST((trans(range<1,2,5>()).nc() == 1));
+
+ DLIB_TEST((range<0,3,6>().nc() == 3));
+ DLIB_TEST((range<1,3,5>().nc() == 2));
+ DLIB_TEST((range<0,3,5>().nr() == 1));
+ DLIB_TEST((range<1,3,5>().nr() == 1));
+ DLIB_TEST((trans(range<0,3,6>()).nr() == 3));
+ DLIB_TEST((trans(range<1,3,5>()).nr() == 2));
+ DLIB_TEST((trans(range<0,3,5>()).nc() == 1));
+ DLIB_TEST((trans(range<1,3,5>()).nc() == 1));
+ }
+
+ {
+ DLIB_TEST(range(5,0).nc() == 6);
+ DLIB_TEST(range(5,1).nc() == 5);
+ DLIB_TEST(range(5,0).nr() == 1);
+ DLIB_TEST(range(5,1).nr() == 1);
+ DLIB_TEST(trans(range(5,0)).nr() == 6);
+ DLIB_TEST(trans(range(5,1)).nr() == 5);
+ DLIB_TEST(trans(range(5,0)).nc() == 1);
+ DLIB_TEST(trans(range(5,1)).nc() == 1);
+
+ DLIB_TEST(range(5,2,0).nc() == 3);
+ DLIB_TEST(range(5,2,1).nc() == 3);
+ DLIB_TEST(range(5,2,0).nr() == 1);
+ DLIB_TEST(range(5,2,1).nr() == 1);
+ DLIB_TEST(trans(range(5,2,0)).nr() == 3);
+ DLIB_TEST(trans(range(5,2,1)).nr() == 3);
+ DLIB_TEST(trans(range(5,2,0)).nc() == 1);
+ DLIB_TEST(trans(range(5,2,1)).nc() == 1);
+
+ DLIB_TEST(range(6,3,0).nc() == 3);
+ DLIB_TEST(range(5,3,1).nc() == 2);
+ DLIB_TEST(range(5,3,0).nr() == 1);
+ DLIB_TEST(range(5,3,1).nr() == 1);
+ DLIB_TEST(trans(range(6,3,0)).nr() == 3);
+ DLIB_TEST(trans(range(5,3,1)).nr() == 2);
+ DLIB_TEST(trans(range(5,3,0)).nc() == 1);
+ DLIB_TEST(trans(range(5,3,1)).nc() == 1);
+
+ DLIB_TEST(range(5,9,1).nc() == 1);
+ DLIB_TEST(range(5,9,1).nr() == 1);
+
+ DLIB_TEST(range(0,0).nc() == 1);
+ DLIB_TEST(range(0,0).nr() == 1);
+
+ DLIB_TEST(range(1,1)(0) == 1);
+
+ DLIB_TEST(range(5,0)(0) == 5 && range(5,0)(1) == 4 && range(5,0)(5) == 0);
+ DLIB_TEST(range(5,2,1)(0) == 5 && range(5,2,1)(1) == 3 && range(5,2,1)(2) == 1);
+ DLIB_TEST((range<5,0>()(0) == 5 && range<5,0>()(1) == 4 && range<5,0>()(5) == 0));
+ DLIB_TEST((range<5,2,1>()(0) == 5 && range<5,2,1>()(1) == 3 && range<5,2,1>()(2) == 1));
+
+
+ DLIB_TEST((range<5,0>().nc() == 6));
+ DLIB_TEST((range<5,1>().nc() == 5));
+ DLIB_TEST((range<5,0>().nr() == 1));
+ DLIB_TEST((range<5,1>().nr() == 1));
+ DLIB_TEST((trans(range<5,0>()).nr() == 6));
+ DLIB_TEST((trans(range<5,1>()).nr() == 5));
+ DLIB_TEST((trans(range<5,0>()).nc() == 1));
+ DLIB_TEST((trans(range<5,1>()).nc() == 1));
+
+ DLIB_TEST((range<5,2,0>().nc() == 3));
+ DLIB_TEST((range<5,2,1>().nc() == 3));
+ DLIB_TEST((range<5,2,0>().nr() == 1));
+ DLIB_TEST((range<5,2,1>().nr() == 1));
+ DLIB_TEST((trans(range<5,2,0>()).nr() == 3));
+ DLIB_TEST((trans(range<5,2,1>()).nr() == 3));
+ DLIB_TEST((trans(range<5,2,0>()).nc() == 1));
+ DLIB_TEST((trans(range<5,2,1>()).nc() == 1));
+
+ DLIB_TEST((range<6,3,0>().nc() == 3));
+ DLIB_TEST((range<5,3,1>().nc() == 2));
+ DLIB_TEST((range<5,3,0>().nr() == 1));
+ DLIB_TEST((range<5,3,1>().nr() == 1));
+ DLIB_TEST((trans(range<6,3,0>()).nr() == 3));
+ DLIB_TEST((trans(range<5,3,1>()).nr() == 2));
+ DLIB_TEST((trans(range<5,3,0>()).nc() == 1));
+ DLIB_TEST((trans(range<5,3,1>()).nc() == 1));
+ }
+
+ {
+ matrix<double> m(4,3);
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ DLIB_TEST(subm(m,range(0,3),range(0,0)) == colm(m,0));
+ DLIB_TEST(subm(m,range(0,3),range(1,1)) == colm(m,1));
+ DLIB_TEST(subm(m,range(0,3),range(2,2)) == colm(m,2));
+
+ DLIB_TEST(subm(m,range(0,0),range(0,2)) == rowm(m,0));
+ DLIB_TEST(subm(m,range(1,1),range(0,2)) == rowm(m,1));
+ DLIB_TEST(subm(m,range(2,2),range(0,2)) == rowm(m,2));
+ DLIB_TEST(subm(m,range(3,3),range(0,2)) == rowm(m,3));
+
+ DLIB_TEST(subm(m,0,0,2,2) == subm(m,range(0,1),range(0,1)));
+ DLIB_TEST(subm(m,1,1,2,2) == subm(m,range(1,2),range(1,2)));
+
+ matrix<double,2,2> m2 = subm(m,range(0,2,2),range(0,2,2));
+
+ DLIB_TEST(m2(0,0) == m(0,0));
+ DLIB_TEST(m2(0,1) == m(0,2));
+ DLIB_TEST(m2(1,0) == m(2,0));
+ DLIB_TEST(m2(1,1) == m(2,2));
+
+
+ }
+ {
+ matrix<double,4,3> m(4,3);
+ for (long r = 0; r < m.nr(); ++r)
+ {
+ for (long c = 0; c < m.nc(); ++c)
+ {
+ m(r,c) = r*c;
+ }
+ }
+
+ DLIB_TEST(subm(m,range<0,3>(),range<0,0>()) == colm(m,0));
+ DLIB_TEST(subm(m,range<0,3>(),range<1,1>()) == colm(m,1));
+ DLIB_TEST(subm(m,range<0,3>(),range<2,2>()) == colm(m,2));
+
+ DLIB_TEST(subm(m,range<0,0>(),range<0,2>()) == rowm(m,0));
+ DLIB_TEST(subm(m,range<1,1>(),range<0,2>()) == rowm(m,1));
+ DLIB_TEST(subm(m,range<2,2>(),range<0,2>()) == rowm(m,2));
+ DLIB_TEST(subm(m,range<3,3>(),range<0,2>()) == rowm(m,3));
+
+ DLIB_TEST(subm(m,0,0,2,2) == subm(m,range<0,1>(),range<0,1>()));
+ DLIB_TEST(subm(m,1,1,2,2) == subm(m,range<1,2>(),range<1,2>()));
+
+ matrix<double,2,2> m2 = subm(m,range<0,2,2>(),range<0,2,2>());
+
+ DLIB_TEST(m2(0,0) == m(0,0));
+ DLIB_TEST(m2(0,1) == m(0,2));
+ DLIB_TEST(m2(1,0) == m(2,0));
+ DLIB_TEST(m2(1,1) == m(2,2));
+
+
+ }
+
+ {
+ matrix<double> a = randm(3,4);
+ matrix<double> b = randm(3,4);
+
+ matrix<double> m1, m2;
+
+ m1 = max_pointwise(a,b);
+ m2 = min_pointwise(a,b);
+ DLIB_TEST(m1.nr() == a.nr());
+ DLIB_TEST(m1.nc() == a.nc());
+ DLIB_TEST(m2.nr() == a.nr());
+ DLIB_TEST(m2.nc() == a.nc());
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ DLIB_TEST_MSG(m1(r,c) == std::max(a(r,c), b(r,c)), m1(r,c) << " : " << a(r,c) << " " << b(r,c));
+ DLIB_TEST(m2(r,c) == std::min(a(r,c), b(r,c)));
+ }
+ }
+ }
+
+ {
+ matrix<double,4,5> m;
+ set_subm(m, range(0,3), range(0,4)) = 4;
+ DLIB_TEST(min(m) == max(m) && min(m) == 4);
+
+ set_subm(m,range(1,1),range(0,4)) = 7;
+ DLIB_TEST((rowm(m,0) == uniform_matrix<double>(1,5, 4)));
+ DLIB_TEST((rowm(m,1) == uniform_matrix<double>(1,5, 7)));
+ DLIB_TEST((rowm(m,2) == uniform_matrix<double>(1,5, 4)));
+ DLIB_TEST((rowm(m,3) == uniform_matrix<double>(1,5, 4)));
+
+
+ set_subm(m, range(0,2,3), range(0,2,4)) = trans(subm(m,0,0,3,2));
+
+
+ DLIB_TEST(m(0,2) == 7);
+ DLIB_TEST(m(2,2) == 7);
+
+ DLIB_TEST(sum(m) == 7*5+ 7+7 + 4*(4*5 - 7));
+
+ }
+
+ {
+ matrix<double> mat(4,5);
+ DLIB_TEST((uniform_matrix<double>(4,5,1) == ones_matrix<double>(4,5)));
+ DLIB_TEST((uniform_matrix<double>(4,5,1) == ones_matrix(mat)));
+ DLIB_TEST((uniform_matrix<double>(4,5,0) == zeros_matrix<double>(4,5)));
+ DLIB_TEST((uniform_matrix<double>(4,5,0) == zeros_matrix(mat)));
+ DLIB_TEST((uniform_matrix<float>(4,5,1) == ones_matrix<float>(4,5)));
+ DLIB_TEST((uniform_matrix<float>(4,5,0) == zeros_matrix<float>(4,5)));
+ DLIB_TEST((uniform_matrix<complex<double> >(4,5,1) == ones_matrix<complex<double> >(4,5)));
+ DLIB_TEST((uniform_matrix<complex<double> >(4,5,0) == zeros_matrix<complex<double> >(4,5)));
+ DLIB_TEST((uniform_matrix<complex<float> >(4,5,1) == ones_matrix<complex<float> >(4,5)));
+ DLIB_TEST((uniform_matrix<complex<float> >(4,5,0) == zeros_matrix<complex<float> >(4,5)));
+ DLIB_TEST((complex_matrix(ones_matrix<double>(3,3), zeros_matrix<double>(3,3)) == complex_matrix(ones_matrix<double>(3,3))));
+ DLIB_TEST((pointwise_multiply(complex_matrix(ones_matrix<double>(3,3)), ones_matrix<double>(3,3)*2) ==
+ complex_matrix(2*ones_matrix<double>(3,3))));
+ }
+
+ {
+ DLIB_TEST(( uniform_matrix<double>(303,303, 3)*identity_matrix<double>(303) == uniform_matrix<double,303,303>(3) ) );
+ DLIB_TEST(( uniform_matrix<double,303,303>(3)*identity_matrix<double,303>() == uniform_matrix<double,303,303>(3) ));
+ }
+
+ {
+ matrix<double> m(2,3);
+ m = 1,2,3,
+ 5,6,7;
+
+ DLIB_TEST_MSG(m(0,0) == 1 && m(0,1) == 2 && m(0,2) == 3 &&
+ m(1,0) == 5 && m(1,1) == 6 && m(1,2) == 7,"");
+
+ m = 4;
+ DLIB_TEST((m == uniform_matrix<double,2,3>(4)));
+
+ matrix<double,2,3> m2;
+ m2 = 1,2,3,
+ 5,6,7;
+ DLIB_TEST_MSG(m2(0,0) == 1 && m2(0,1) == 2 && m2(0,2) == 3 &&
+ m2(1,0) == 5 && m2(1,1) == 6 && m2(1,2) == 7,"");
+
+ matrix<double,2,1> m3;
+ m3 = 1,
+ 5;
+ DLIB_TEST(m3(0) == 1 && m3(1) == 5 );
+
+ matrix<double,1,2> m4;
+ m4 = 1, 5;
+ DLIB_TEST(m3(0) == 1 && m3(1) == 5 );
+ }
+
+ {
+ matrix<double> m(4,1);
+ m = 3, 1, 5, 2;
+ DLIB_TEST(index_of_min(m) == 1);
+ DLIB_TEST(index_of_max(m) == 2);
+ DLIB_TEST(index_of_min(trans(m)) == 1);
+ DLIB_TEST(index_of_max(trans(m)) == 2);
+ }
+
+ {
+ matrix<double> m1(1,5), m2;
+
+ m1 = 3.0000, 3.7500, 4.5000, 5.2500, 6.0000;
+ m2 = linspace(3, 6, 5);
+
+ DLIB_TEST(equal(m1, m2));
+
+ m1 = pow(10, m1);
+ m2 = logspace(3, 6, 5);
+
+ DLIB_TEST(equal(m1, m2));
+ }
+
+ {
+ matrix<long> m = cartesian_product(range(1,3), range(0,1));
+
+ matrix<long,2,1> c0, c1, c2, c3, c4, c5;
+ c0 = 1, 0;
+ c1 = 1, 1;
+ c2 = 2, 0;
+ c3 = 2, 1;
+ c4 = 3, 0;
+ c5 = 3, 1;
+
+ DLIB_TEST_MSG(colm(m,0) == c0, colm(m,0) << "\n\n" << c0);
+ DLIB_TEST(colm(m,1) == c1);
+ DLIB_TEST(colm(m,2) == c2);
+ DLIB_TEST(colm(m,3) == c3);
+ DLIB_TEST(colm(m,4) == c4);
+ DLIB_TEST(colm(m,5) == c5);
+ }
+
+
+ {
+ matrix<double> m(2,2), mr(2,2), mr_max(2,2);
+
+ m = 1, 2,
+ 0, 4;
+
+ mr = 1, 1.0/2.0,
+ 0, 1.0/4.0;
+
+ mr_max = 1, 1.0/2.0,
+ std::numeric_limits<double>::max(), 1.0/4.0;
+
+ DLIB_TEST(equal(reciprocal(m), mr));
+ DLIB_TEST(equal(reciprocal_max(m), mr_max));
+
+ }
+
+ {
+ matrix<double> m1, m2;
+ m1.set_size(3,1);
+ m2.set_size(1,3);
+
+ m1 = 1,2,3;
+ m2 = 4,5,6;
+ DLIB_TEST(dot(m1, m2) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(m1, trans(m2)) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(trans(m1), m2) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(trans(m1), trans(m2)) == 1*4 + 2*5 + 3*6);
+ }
+
+ {
+ matrix<double,3,1> m1, m2;
+ m1.set_size(3,1);
+ m2.set_size(3,1);
+
+ m1 = 1,2,3;
+ m2 = 4,5,6;
+ DLIB_TEST(dot(m1, m2) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(m1, trans(m2)) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(trans(m1), m2) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(trans(m1), trans(m2)) == 1*4 + 2*5 + 3*6);
+ }
+ {
+ matrix<double,1,3> m1, m2;
+ m1.set_size(1,3);
+ m2.set_size(1,3);
+
+ m1 = 1,2,3;
+ m2 = 4,5,6;
+ DLIB_TEST(dot(m1, m2) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(m1, trans(m2)) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(trans(m1), m2) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(trans(m1), trans(m2)) == 1*4 + 2*5 + 3*6);
+ }
+ {
+ matrix<double,1,3> m1;
+ matrix<double> m2;
+ m1.set_size(1,3);
+ m2.set_size(3,1);
+
+ m1 = 1,2,3;
+ m2 = 4,5,6;
+ DLIB_TEST(dot(m1, m2) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(m1, trans(m2)) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(trans(m1), m2) == 1*4 + 2*5 + 3*6);
+ DLIB_TEST(dot(trans(m1), trans(m2)) == 1*4 + 2*5 + 3*6);
+ }
+
+ {
+ matrix<double> m1(3,3), m2(3,3);
+
+ m1 = 1;
+ m2 = 1;
+ m1 = m1*subm(m2,0,0,3,3);
+ DLIB_TEST(is_finite(m1));
+ }
+ {
+ matrix<double,3,1> m1;
+ matrix<double> m2(3,3);
+
+ m1 = 1;
+ m2 = 1;
+ m1 = subm(m2,0,0,3,3)*m1;
+ }
+
+ {
+ matrix<int> m(2,1);
+
+ m = 3,3;
+ m /= m(0);
+
+ DLIB_TEST(m(0) == 1);
+ DLIB_TEST(m(1) == 1);
+ }
+ {
+ matrix<int> m(2,1);
+
+ m = 3,3;
+ m *= m(0);
+
+ DLIB_TEST(m(0) == 9);
+ DLIB_TEST(m(1) == 9);
+ }
+ {
+ matrix<int> m(2,1);
+
+ m = 3,3;
+ m -= m(0);
+
+ DLIB_TEST(m(0) == 0);
+ DLIB_TEST(m(1) == 0);
+ }
+ {
+ matrix<int> m(2,1);
+
+ m = 3,3;
+ m += m(0);
+
+ DLIB_TEST(m(0) == 6);
+ DLIB_TEST(m(1) == 6);
+ DLIB_TEST(is_finite(m));
+ }
+
+
+ {
+ matrix<double> m(3,3);
+ m = 3;
+ m(1,1) = std::numeric_limits<double>::infinity();
+ DLIB_TEST(is_finite(m) == false);
+ m(1,1) = -std::numeric_limits<double>::infinity();
+ DLIB_TEST(is_finite(m) == false);
+ m(1,1) = 2;
+ DLIB_TEST(is_finite(m));
+ }
+
+ {
+ matrix<int> m(4,1), mm, mmm;
+
+ mmm = mm = (m = 1,2,3,4);
+ DLIB_TEST(m(0) == 1);
+ DLIB_TEST(m(1) == 2);
+ DLIB_TEST(m(2) == 3);
+ DLIB_TEST(m(3) == 4);
+ DLIB_TEST(mm == m);
+ DLIB_TEST(mmm == m);
+ DLIB_TEST(mm(0) == 1);
+ DLIB_TEST(mm(1) == 2);
+ DLIB_TEST(mm(2) == 3);
+ DLIB_TEST(mm(3) == 4);
+ }
+
+ {
+ const long n = 5;
+ matrix<double> m1, m2, m3, truth;
+ m1 = randm(n,n);
+ m2 = randm(n,n);
+
+ rectangle rect1(1,1,3,3);
+ rectangle rect2(2,1,4,3);
+
+ truth = subm(m1,rect1)*subm(m2,rect2);
+ m3 = mat(&m1(0,0)+6, 3,3, m1.nc()) * mat(&m2(0,0)+7, 3,3, m2.nc());
+
+ DLIB_TEST(max(abs(truth-m3)) < 1e-13);
+ }
+
+ {
+ const long n = 5;
+ matrix<double> m1, m2, m3, truth;
+ m1 = randm(n,n);
+ m2 = randm(n,n);
+ m3 = randm(n,n);
+
+
+ truth = m1*m2;
+ m3 = mat(&m1(0,0),n,n)*mat(&m2(0,0),n,n);
+ DLIB_TEST(max(abs(truth-m3)) < 1e-13);
+ m3 = 0;
+ set_ptrm(&m3(0,0),n,n) = mat(&m1(0,0),n,n)*mat(&m2(0,0),n,n);
+ DLIB_TEST(max(abs(truth-m3)) < 1e-13);
+ set_ptrm(&m3(0,0),n,n) = m1*m2;
+ DLIB_TEST(max(abs(truth-m3)) < 1e-13);
+
+ // now make sure it deals with aliasing correctly.
+ truth = m1*m2;
+ m1 = mat(&m1(0,0),n,n)*mat(&m2(0,0),n,n);
+ DLIB_TEST(max(abs(truth-m1)) < 1e-13);
+
+ m1 = randm(n,n);
+ truth = m1*m2;
+ set_ptrm(&m1(0,0),n,n) = mat(&m1(0,0),n,n)*mat(&m2(0,0),n,n);
+ DLIB_TEST(max(abs(truth-m1)) < 1e-13);
+
+ m1 = randm(n,n);
+ truth = m1*m2;
+ set_ptrm(&m1(0,0),n,n) = m1*m2;
+ DLIB_TEST(max(abs(truth-m1)) < 1e-13);
+
+ m1 = randm(n,n);
+ truth = m1+m1*m2;
+ set_ptrm(&m1(0,0),n,n) += m1*m2;
+ DLIB_TEST(max(abs(truth-m1)) < 1e-13);
+
+ m1 = randm(n,n);
+ truth = m1-m1*m2;
+ set_ptrm(&m1(0,0),n,n) -= m1*m2;
+ DLIB_TEST(max(abs(truth-m1)) < 1e-13);
+
+ }
+
+ {
+ matrix<double,3,3,default_memory_manager,column_major_layout> a(3,3);
+ matrix<double,3,3,default_memory_manager,column_major_layout> m = randm(3,3);
+ matrix<double,3,1,default_memory_manager,column_major_layout> b = randm(3,1);
+
+ a = 0;
+ set_colm(a,0) = m*b;
+ DLIB_TEST(colm(a,0) == m*b);
+ a = 0;
+ set_rowm(a,0) = trans(m*b);
+ DLIB_TEST(rowm(a,0) == trans(m*b));
+ DLIB_TEST(rowm(a,0) != m*b);
+ }
+ {
+ matrix<double,0,0,default_memory_manager,column_major_layout> a(3,3);
+ matrix<double,0,0,default_memory_manager,column_major_layout> m = randm(3,3);
+ matrix<double,0,0,default_memory_manager,column_major_layout> b = randm(3,1);
+
+ a = 0;
+ set_colm(a,0) = m*b;
+ DLIB_TEST(equal(colm(a,0) , m*b));
+ a = 0;
+ set_rowm(a,0) = trans(m*b);
+ DLIB_TEST(equal(rowm(a,0) , trans(m*b)));
+ DLIB_TEST(!equal(rowm(a,0) , m*b));
+ }
+ {
+ matrix<double> a(3,3);
+ matrix<double> m = randm(3,3);
+ matrix<double> b = randm(3,1);
+
+ a = 0;
+ set_colm(a,0) = m*b;
+ DLIB_TEST(equal(colm(a,0) , m*b));
+ a = 0;
+ set_rowm(a,0) = trans(m*b);
+ DLIB_TEST(equal(rowm(a,0) , trans(m*b)));
+ DLIB_TEST(!equal(rowm(a,0) , m*b));
+ }
+ }
+
+
+
+
+
+
+ class matrix_tester : public tester
+ {
+ public:
+ matrix_tester (
+ ) :
+ tester ("test_matrix",
+ "Runs tests on the matrix component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ matrix_test();
+ matrix_test2();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/matrix2.cpp b/ml/dlib/dlib/test/matrix2.cpp
new file mode 100644
index 000000000..8de17fc7f
--- /dev/null
+++ b/ml/dlib/dlib/test/matrix2.cpp
@@ -0,0 +1,1158 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+
+#include "tester.h"
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/array2d.h>
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.matrix2");
+
+ dlib::rand rnd;
+
+ void matrix_test1 (
+ )
+ {
+ typedef memory_manager_stateless<char>::kernel_2_2a MM;
+ print_spinner();
+
+ const double ident[] = {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1 };
+
+ const double uniform3[] = {
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3
+ };
+
+ const double uniform1[] = {
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1
+ };
+
+ const double uniform0[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+ };
+
+ const int array[] = {
+ 42, 58, 9, 1,
+ 9, 5, 8, 2,
+ 98, 28, 4, 77,
+ 9, 2, 44, 88 };
+
+ const int array2[] = {
+ 1, 22, 3,
+ 4, 52, 6,
+ 7, 8, 9 };
+
+ const int array2_r[] = {
+ 52, 6, 4,
+ 8, 9, 7,
+ 22, 3, 1
+ };
+
+ const double array_f[] = {
+ -0.99,
+ 0.99};
+
+
+ matrix<double,2,1,MM> fm(array_f);
+
+ DLIB_TEST(fm.size() == 2);
+ matrix<double> dfm(fm);
+ DLIB_TEST(round(fm)(0) == -1);
+ DLIB_TEST(round(fm)(1) == 1);
+ DLIB_TEST(round(dfm)(0) == -1);
+ DLIB_TEST(round(dfm)(1) == 1);
+ DLIB_TEST(round(dfm).size() == dfm.size());
+
+
+ const int array3[] = { 1, 2, 3, 4 };
+
+ matrix<double,3,3,MM> m3(array2);
+ matrix<double> dm3;
+ DLIB_TEST(dm3.size() == 0);
+ DLIB_TEST(dm3.nr() == 0);
+ DLIB_TEST(dm3.nc() == 0);
+ dm3.set_size(3,4);
+ DLIB_TEST(dm3.nr() == 3);
+ DLIB_TEST(dm3.nc() == 4);
+ DLIB_TEST(dm3.size() == 3*4);
+ dm3.set_size(3,3);
+ DLIB_TEST(dm3.nr() == 3);
+ DLIB_TEST(dm3.nc() == 3);
+ dm3 = m3;
+ dm3(0,0)++;
+ DLIB_TEST( dm3 != m3);
+ dm3 = m3;
+ DLIB_TEST( dm3 == m3);
+ DLIB_TEST( abs(sum(squared(normalize(dm3))) - 1.0) < 1e-10);
+
+ matrix<double,3,4> mrc;
+ mrc.set_size(3,4);
+
+ set_all_elements(mrc,1);
+
+ DLIB_TEST(diag(mrc) == uniform_matrix<double>(3,1,1));
+ DLIB_TEST(diag(matrix<double>(mrc)) == uniform_matrix<double>(3,1,1));
+
+ matrix<double,2,3> mrc2;
+ set_all_elements(mrc2,1);
+ DLIB_TEST((removerc<1,1>(mrc) == mrc2));
+ DLIB_TEST((removerc(mrc,1,1) == mrc2));
+
+ matrix<int,3,3> m4, m5, m6;
+ set_all_elements(m4, 4);
+ set_all_elements(m5, 4);
+ set_all_elements(m6, 1);
+
+ DLIB_TEST(squared(m4) == pointwise_multiply(m4,m4));
+ DLIB_TEST(cubed(m4) == pointwise_multiply(m4,m4,m4));
+ DLIB_TEST(pow(matrix_cast<double>(m4),2) == squared(matrix_cast<double>(m4)));
+ DLIB_TEST(pow(matrix_cast<double>(m4),3) == cubed(matrix_cast<double>(m4)));
+
+ matrix<int> dm4;
+ matrix<int,0,0,memory_manager_stateless<char>::kernel_2_2a> dm5;
+ dm4 = dm4;
+ dm4 = dm5;
+ DLIB_TEST(dm4.nr() == 0);
+ dm4 = m4;
+ dm5 = m5;
+ DLIB_TEST(dm4 == dm5);
+
+
+ DLIB_TEST(m4 == m5);
+ DLIB_TEST(m6 != m5);
+ m4.swap(m6);
+ DLIB_TEST(m6 == m5);
+ DLIB_TEST(m4 != m5);
+
+ DLIB_TEST(m3.nr() == 3);
+ DLIB_TEST(m3.nc() == 3);
+
+ matrix<double,4,1> v(array3), v2;
+ DLIB_TEST(v.nr() == 4);
+ DLIB_TEST(v.nc() == 1);
+
+ std::vector<double> stdv(4);
+ std_vector_c<double> stdv_c(4);
+ dlib::array<double> arr;
+ arr.resize(4);
+ for (long i = 0; i < 4; ++i)
+ stdv[i] = stdv_c[i] = arr[i] = i+1;
+
+ DLIB_TEST(mat(stdv)(0) == 1);
+ DLIB_TEST(mat(stdv)(1) == 2);
+ DLIB_TEST(mat(stdv)(2) == 3);
+ DLIB_TEST(mat(stdv)(3) == 4);
+ DLIB_TEST(mat(stdv).nr() == 4);
+ DLIB_TEST(mat(stdv).nc() == 1);
+ DLIB_TEST(mat(stdv).size() == 4);
+ DLIB_TEST(equal(trans(mat(stdv))*mat(stdv), trans(v)*v));
+ DLIB_TEST(equal(trans(mat(stdv))*mat(stdv), tmp(trans(v)*v)));
+
+ DLIB_TEST(mat(stdv_c)(0) == 1);
+ DLIB_TEST(mat(stdv_c)(1) == 2);
+ DLIB_TEST(mat(stdv_c)(2) == 3);
+ DLIB_TEST(mat(stdv_c)(3) == 4);
+ DLIB_TEST(mat(stdv_c).nr() == 4);
+ DLIB_TEST(mat(stdv_c).nc() == 1);
+ DLIB_TEST(mat(stdv_c).size() == 4);
+ DLIB_TEST(equal(trans(mat(stdv_c))*mat(stdv_c), trans(v)*v));
+
+ DLIB_TEST(mat(arr)(0) == 1);
+ DLIB_TEST(mat(arr)(1) == 2);
+ DLIB_TEST(mat(arr)(2) == 3);
+ DLIB_TEST(mat(arr)(3) == 4);
+ DLIB_TEST(mat(arr).nr() == 4);
+ DLIB_TEST(mat(arr).nc() == 1);
+ DLIB_TEST(mat(arr).size() == 4);
+ DLIB_TEST(equal(trans(mat(arr))*mat(arr), trans(v)*v));
+
+ DLIB_TEST(v(0) == 1);
+ DLIB_TEST(v(1) == 2);
+ DLIB_TEST(v(2) == 3);
+ DLIB_TEST(v(3) == 4);
+ matrix<double> dv = v;
+ DLIB_TEST((trans(v)*v).size() == 1);
+ DLIB_TEST((trans(v)*v).nr() == 1);
+ DLIB_TEST((trans(v)*dv).nr() == 1);
+ DLIB_TEST((trans(dv)*dv).nr() == 1);
+ DLIB_TEST((trans(dv)*v).nr() == 1);
+ DLIB_TEST((trans(v)*v).nc() == 1);
+ DLIB_TEST((trans(v)*dv).nc() == 1);
+ DLIB_TEST((trans(dv)*dv).nc() == 1);
+ DLIB_TEST((trans(dv)*v).nc() == 1);
+ DLIB_TEST((trans(v)*v)(0) == 1*1 + 2*2 + 3*3 + 4*4);
+ DLIB_TEST((trans(dv)*v)(0) == 1*1 + 2*2 + 3*3 + 4*4);
+ DLIB_TEST((trans(dv)*dv)(0) == 1*1 + 2*2 + 3*3 + 4*4);
+ DLIB_TEST((trans(v)*dv)(0) == 1*1 + 2*2 + 3*3 + 4*4);
+
+ dv = trans(dv)*v;
+ DLIB_TEST(dv.nr() == 1);
+ DLIB_TEST(dv.nc() == 1);
+
+ dm3 = m3;
+ DLIB_TEST(floor(det(m3)+0.01) == -444);
+ DLIB_TEST(floor(det(dm3)+0.01) == -444);
+ DLIB_TEST(min(m3) == 1);
+ DLIB_TEST(m3(min_point(m3).y(),min_point(m3).x()) == 1);
+ DLIB_TEST(min(dm3) == 1);
+ DLIB_TEST(max(m3) == 52);
+ DLIB_TEST(m3(max_point(m3).y(),max_point(m3).x()) == 52);
+ DLIB_TEST(max(dm3) == 52);
+ DLIB_TEST(sum(m3) == 112);
+ DLIB_TEST(sum(dm3) == 112);
+ DLIB_TEST(prod(m3) == 41513472);
+ DLIB_TEST(prod(dm3) == 41513472);
+ DLIB_TEST(prod(diag(m3)) == 1*52*9);
+ DLIB_TEST(prod(diag(dm3)) == 1*52*9);
+ DLIB_TEST(sum(diag(m3)) == 1+52+9);
+ DLIB_TEST(sum(diag(dm3)) == 1+52+9);
+ DLIB_TEST(equal(round(10000*m3*inv(m3))/10000 , identity_matrix<double,3>()));
+ DLIB_TEST(equal(round(10000*dm3*inv(m3))/10000 , identity_matrix<double,3>()));
+ DLIB_TEST(equal(round(10000*dm3*inv(dm3))/10000 , identity_matrix<double,3>()));
+ DLIB_TEST(equal(round(10000*m3*inv(dm3))/10000 , identity_matrix<double,3>()));
+ DLIB_TEST(equal(round(10000*tmp(m3*inv(m3)))/10000 , identity_matrix<double,3>()));
+ DLIB_TEST(equal(round(10000*tmp(dm3*inv(m3)))/10000 , identity_matrix<double,3>()));
+ DLIB_TEST(equal(round(10000*tmp(dm3*inv(dm3)))/10000 , identity_matrix<double,3>()));
+ DLIB_TEST(equal(round(10000*tmp(m3*inv(dm3)))/10000 , identity_matrix<double,3>()));
+ DLIB_TEST(-1*m3 == -m3);
+ DLIB_TEST(-1*dm3 == -m3);
+ DLIB_TEST(-1*m3 == -dm3);
+ DLIB_TEST(-1*dm3 == -dm3);
+
+ DLIB_TEST(m3 == dm3);
+ m3(1,1) = 99;
+ DLIB_TEST(m3 != dm3);
+ m3 = dm3;
+ DLIB_TEST(m3 == dm3);
+
+ matrix<double,4,4,MM> mident(ident);
+ matrix<double,4,4> muniform0(uniform0);
+ matrix<double,4,4> muniform1(uniform1);
+ matrix<double,4,4> muniform3(uniform3);
+ matrix<double,4,4> m1(array), m2;
+ DLIB_TEST(m1.nr() == 4);
+ DLIB_TEST(m1.nc() == 4);
+
+ DLIB_TEST(muniform1 + muniform1 + muniform1 == muniform3);
+ DLIB_TEST(muniform1*2 + muniform1 + muniform1 - muniform1 == muniform3);
+ DLIB_TEST(2*muniform1 + muniform1 + muniform1 - muniform1 == muniform3);
+ DLIB_TEST(muniform1 + muniform1 + muniform1 - muniform3 == muniform0);
+ DLIB_TEST(equal(muniform3/3 , muniform1));
+ DLIB_TEST(v != m1);
+ DLIB_TEST(v == v);
+ DLIB_TEST(m1 == m1);
+
+ muniform0.swap(muniform1);
+ DLIB_TEST((muniform1 == matrix_cast<double>(uniform_matrix<long,4,4,0>())));
+ DLIB_TEST((muniform0 == matrix_cast<double>(uniform_matrix<long,4,4,1>())));
+ DLIB_TEST((muniform1 == matrix_cast<double>(uniform_matrix<long>(4,4,0))));
+ DLIB_TEST((muniform0 == matrix_cast<double>(uniform_matrix<long>(4,4,1))));
+ swap(muniform0,muniform1);
+
+ DLIB_TEST((mident == identity_matrix<double,4>()));
+ DLIB_TEST((muniform0 == matrix_cast<double>(uniform_matrix<long,4,4,0>())));
+ DLIB_TEST((muniform1 == matrix_cast<double>(uniform_matrix<long,4,4,1>())));
+ DLIB_TEST((muniform3 == matrix_cast<double>(uniform_matrix<long,4,4,3>())));
+ DLIB_TEST((muniform1*8 == matrix_cast<double>(uniform_matrix<long,4,4,8>())));
+
+ set_all_elements(m2,7);
+ DLIB_TEST(m2 == muniform1*7);
+ m2 = array;
+ DLIB_TEST(m2 == m1);
+
+ const double m1inv[] = {
+ -0.00946427624, 0.0593272941, 0.00970564379, -0.00973323731,
+ 0.0249312057, -0.0590122427, -0.00583102756, 0.00616002729,
+ -0.00575431149, 0.110081189, -0.00806792253, 0.00462297692,
+ 0.00327847478, -0.0597669712, 0.00317386196, 0.00990759201
+ };
+
+ m2 = m1inv;
+ DLIB_TEST((round(m2*m1) == identity_matrix<double,4>()));
+ DLIB_TEST((round(tmp(m2*m1)) == identity_matrix<double,4>()));
+
+ DLIB_TEST_MSG(round(m2*10000) == round(inv(m1)*10000),
+ round(m2*10000) - round(inv(m1)*10000)
+ << "\n\n" << round(m2*10000)
+ << "\n\n" << round(inv(m1)*10000)
+ << "\n\n" << m2
+ << "\n\n" << inv(m1)
+ );
+ DLIB_TEST(m1 == abs(-1*m1));
+ DLIB_TEST(abs(m2) == abs(-1*m2));
+
+ DLIB_TEST_MSG(floor(det(m1)+0.01) == 3297875,"\nm1: \n" << m1 << "\ndet(m1): " << det(m1));
+
+
+ ostringstream sout;
+ m1 = m2;
+ serialize(m1,sout);
+ set_all_elements(m1,0);
+ istringstream sin(sout.str());
+ deserialize(m1,sin);
+ DLIB_TEST_MSG(round(100000*m1) == round(100000*m2),"m1: \n" << m1 << endl << "m2: \n" << m2);
+
+
+ set_all_elements(v,2);
+ v2 = pointwise_multiply(v, v*2);
+ set_all_elements(v,8);
+ DLIB_TEST(v == v2);
+ DLIB_TEST(v == tmp(v2));
+ DLIB_TEST((v == rotate<2,0>(v)));
+
+ m4 = array2;
+ m5 = array2_r;
+ DLIB_TEST((m5 == rotate<1,1>(m4)));
+
+ m5 = array2;
+ DLIB_TEST((m5*2 == pointwise_multiply(m5,uniform_matrix<int,3,3,2>())));
+ DLIB_TEST((tmp(m5*2) == tmp(pointwise_multiply(m5,uniform_matrix<int,3,3,2>()))));
+
+ v = tmp(v);
+
+
+
+
+ matrix<double> dm10(10,5);
+ DLIB_TEST(dm10.nr() == 10);
+ DLIB_TEST(dm10.nc() == 5);
+ set_all_elements(dm10,4);
+ DLIB_TEST(dm10.nr() == 10);
+ DLIB_TEST(dm10.nc() == 5);
+ matrix<double,10,5> m10;
+ DLIB_TEST(m10.nr() == 10);
+ DLIB_TEST(m10.nc() == 5);
+ set_all_elements(m10,4);
+ DLIB_TEST(dm10 == m10);
+ DLIB_TEST((clamp<0,3>(dm10) == clamp<0,3>(m10)));
+ DLIB_TEST((clamp<0,3>(dm10)(0,2) == 3));
+
+ set_all_elements(dm10,1);
+ set_all_elements(m10,4);
+ DLIB_TEST(4*dm10 == m10);
+ DLIB_TEST(5*dm10 - dm10 == m10);
+ DLIB_TEST((16*dm10)/4 == m10);
+ DLIB_TEST(dm10+dm10+2*dm10 == m10);
+ DLIB_TEST(dm10+tmp(dm10+2*dm10) == m10);
+ set_all_elements(dm10,4);
+ DLIB_TEST(dm10 == m10);
+ DLIB_TEST_MSG(sum(abs(sigmoid(dm10) -sigmoid(m10))) < 1e-10,sum(abs(sigmoid(dm10) -sigmoid(m10))) );
+
+ {
+ matrix<double,2,1> x, l, u, out;
+ x = 3,4;
+
+ l = 1,1;
+ u = 2,2.2;
+
+ out = 2, 2.2;
+ DLIB_TEST(equal(dlib::clamp(x, l, u) , out));
+ out = 3, 2.2;
+ DLIB_TEST(!equal(dlib::clamp(x, l, u) , out));
+ out = 2, 4.2;
+ DLIB_TEST(!equal(dlib::clamp(x, l, u) , out));
+
+ x = 1.5, 1.5;
+ out = x;
+ DLIB_TEST(equal(dlib::clamp(x, l, u) , out));
+
+ x = 0.5, 1.5;
+ out = 1, 1.5;
+ DLIB_TEST(equal(dlib::clamp(x, l, u) , out));
+
+ x = 1.5, 0.5;
+ out = 1.5, 1.0;
+ DLIB_TEST(equal(dlib::clamp(x, l, u) , out));
+
+ }
+
+ matrix<double, 7, 7,MM,column_major_layout> m7;
+ matrix<double> dm7(7,7);
+ dm7 = randm(7,7, rnd);
+ m7 = dm7;
+
+ DLIB_TEST_MSG(max(abs(dm7*inv(dm7) - identity_matrix<double>(7))) < 1e-12, max(abs(dm7*inv(dm7) - identity_matrix<double>(7))));
+ DLIB_TEST(equal(inv(dm7), inv(m7)));
+ DLIB_TEST(abs(det(dm7) - det(m7)) < 1e-14);
+ DLIB_TEST(abs(min(dm7) - min(m7)) < 1e-14);
+ DLIB_TEST(abs(max(dm7) - max(m7)) < 1e-14);
+ DLIB_TEST_MSG(abs(sum(dm7) - sum(m7)) < 1e-13,sum(dm7) - sum(m7));
+ DLIB_TEST(abs(prod(dm7) -prod(m7)) < 1e-14);
+ DLIB_TEST(equal(diag(dm7) , diag(m7)));
+ DLIB_TEST(equal(trans(dm7) , trans(m7)));
+ DLIB_TEST(equal(abs(dm7) , abs(m7)));
+ DLIB_TEST(equal(round(dm7) , round(m7)));
+ DLIB_TEST(matrix_cast<int>(dm7) == matrix_cast<int>(m7));
+ DLIB_TEST((rotate<2,3>(dm7) == rotate<2,3>(m7)));
+ DLIB_TEST((sum(pointwise_multiply(dm7,dm7) - pointwise_multiply(m7,m7))) < 1e-10);
+ DLIB_TEST((sum(pointwise_multiply(dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7))) < 1e-10);
+ DLIB_TEST_MSG((sum(pointwise_multiply(dm7,dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7,m7))) < 1e-10,
+ (sum(pointwise_multiply(dm7,dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7,m7)))
+ );
+
+
+ matrix<double> temp(5,5);
+ matrix<double> dsm(5,5);
+ matrix<double,5,5,MM> sm;
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,1);
+
+ dsm += dsm;
+ sm += sm;
+ DLIB_TEST(dsm == 2*temp);
+ DLIB_TEST(sm == 2*temp);
+ temp = dsm*sm + dsm;
+ dsm += dsm*sm;
+ DLIB_TEST_MSG(temp == dsm,temp - dsm);
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,1);
+
+ dsm += dsm;
+ sm += sm;
+ DLIB_TEST(dsm == 2*temp);
+ DLIB_TEST(sm == 2*temp);
+ temp = dsm*sm + dsm;
+ sm += dsm*sm;
+ DLIB_TEST_MSG(temp == sm,temp - sm);
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,1);
+
+ dsm += dsm;
+ sm += sm;
+ DLIB_TEST(dsm == 2*temp);
+ DLIB_TEST(sm == 2*temp);
+ temp = sm - dsm*sm ;
+ sm -= dsm*sm;
+ DLIB_TEST_MSG(temp == sm,temp - sm);
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,1);
+
+ dsm += dsm;
+ sm += sm;
+ DLIB_TEST(dsm == 2*temp);
+ DLIB_TEST(sm == 2*temp);
+ temp = dsm - dsm*sm ;
+ dsm -= dsm*sm;
+ DLIB_TEST_MSG(temp == dsm,temp - dsm);
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,2);
+
+ dsm *= 2;
+ sm *= 2;
+ DLIB_TEST(dsm == temp);
+ DLIB_TEST(sm == temp);
+ dsm /= 2;
+ sm /= 2;
+ DLIB_TEST(dsm == temp/2);
+ DLIB_TEST(sm == temp/2);
+
+ dsm += dsm;
+ sm += sm;
+ DLIB_TEST(dsm == temp);
+ DLIB_TEST(sm == temp);
+ dsm += sm;
+ sm += dsm;
+ DLIB_TEST(dsm == 2*temp);
+ DLIB_TEST(sm == temp*3);
+ dsm -= sm;
+ sm -= dsm;
+ DLIB_TEST(dsm == -temp);
+ DLIB_TEST(sm == 4*temp);
+ sm -= sm;
+ dsm -= dsm;
+ DLIB_TEST(dsm == 0*temp);
+ DLIB_TEST(sm == 0*temp);
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,3);
+ dsm += sm+sm;
+ DLIB_TEST(dsm == temp);
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,-1);
+ dsm -= sm+sm;
+ DLIB_TEST(dsm == temp);
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,-1);
+ sm -= dsm+dsm;
+ DLIB_TEST(sm == temp);
+
+ set_all_elements(dsm,1);
+ set_all_elements(sm,1);
+ set_all_elements(temp,3);
+ sm += dsm+dsm;
+ DLIB_TEST(sm == temp);
+
+
+
+ // test the implicit conversion to bool stuff
+ {
+ matrix<float> bt1(3,1);
+ matrix<float,3,1> bt2;
+ set_all_elements(bt1,2);
+ set_all_elements(bt2,3);
+
+ float val = trans(bt1)*bt2;
+ DLIB_TEST((float)(trans(bt1)*bt2) == 18);
+ DLIB_TEST((float)(trans(bt1)*bt2) != 19);
+ DLIB_TEST(val == 18);
+ }
+ {
+ matrix<float,3,1> bt1;
+ matrix<float> bt2(3,1);
+ set_all_elements(bt1,2);
+ set_all_elements(bt2,3);
+
+ float val = trans(bt1)*bt2;
+ DLIB_TEST((float)(trans(bt1)*bt2) == 18);
+ DLIB_TEST((float)(trans(bt1)*bt2) != 19);
+ DLIB_TEST(val == 18);
+ }
+ {
+ matrix<float> bt1(3,1);
+ matrix<float> bt2(3,1);
+ set_all_elements(bt1,2);
+ set_all_elements(bt2,3);
+
+ float val = trans(bt1)*bt2;
+ DLIB_TEST((float)(trans(bt1)*bt2) == 18);
+ DLIB_TEST((float)(trans(bt1)*bt2) != 19);
+ DLIB_TEST(val == 18);
+ }
+ {
+ matrix<float,3,1> bt1;
+ matrix<float,3,1> bt2;
+ set_all_elements(bt1,2);
+ set_all_elements(bt2,3);
+
+ float val = trans(bt1)*bt2;
+ DLIB_TEST((float)(trans(bt1)*bt2) == 18);
+ DLIB_TEST((float)(trans(bt1)*bt2) != 19);
+ DLIB_TEST(val == 18);
+ }
+
+
+
+
+ {
+ srand(423452);
+ const long M = 50;
+ const long N = 40;
+
+ matrix<double> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double> u, u2;
+ matrix<double> q, q2;
+ matrix<double> v, v2;
+
+ matrix<double> a2;
+ a2 = tmp(a/2);
+
+
+ svd2(true,true,a2+a2,u,q,v);
+
+ double err = max(abs(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v)));
+ DLIB_TEST_MSG( err < 1e-11,"err: " << err);
+ using dlib::equal;
+ DLIB_TEST((equal(trans(u)*u , identity_matrix<double,M>(), 1e-10)));
+ DLIB_TEST((equal(trans(v)*v , identity_matrix<double,N>(), 1e-10)));
+
+ svd2(false,true,a2+a2,u,q,v2);
+ svd2(true,false,a2+a2,u2,q,v);
+ svd2(false,false,a2+a2,u,q2,v);
+
+ err = max(abs(a - subm(u2,get_rect(a2+a2))*diagm(q2)*trans(v2)));
+ DLIB_TEST_MSG( err < 1e-11,"err: " << err);
+ DLIB_TEST((equal(trans(u2)*u2 , identity_matrix<double,M>(), 1e-10)));
+ DLIB_TEST((equal(trans(v2)*v2 , identity_matrix<double,N>(), 1e-10)));
+
+ }
+
+
+ {
+ srand(423452);
+ const long M = 3;
+ const long N = 3;
+
+ matrix<double> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double,M,M> u, u2;
+ matrix<double> q, q2;
+ matrix<double,N,N> v, v2;
+
+ matrix<double,M,N,MM> a2;
+ a2 = tmp(a/2);
+
+
+ svd2(true,true,a2+a2,u,q,v);
+
+ double err = max(abs(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v)));
+ DLIB_TEST_MSG( err < 1e-11,"err: " << err);
+ using dlib::equal;
+ DLIB_TEST((equal(trans(u)*u , identity_matrix<double,M>(), 1e-10)));
+ DLIB_TEST((equal(trans(v)*v , identity_matrix<double,N>(), 1e-10)));
+
+ svd2(false,true,a2+a2,u,q,v2);
+ svd2(true,false,a2+a2,u2,q,v);
+ svd2(false,false,a2+a2,u,q2,v);
+
+ err = max(abs(a - subm(u2,get_rect(a2+a2))*diagm(q2)*trans(v2)));
+ DLIB_TEST_MSG( err < 1e-11,"err: " << err);
+ DLIB_TEST((equal(trans(u2)*u2 , identity_matrix<double,M>(), 1e-10)));
+ DLIB_TEST((equal(trans(v2)*v2 , identity_matrix<double,N>(), 1e-10)));
+
+ }
+
+ {
+ srand(423452);
+ const long M = 3;
+ const long N = 3;
+
+
+ matrix<double,0,0,default_memory_manager, column_major_layout> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double,M,M,default_memory_manager, column_major_layout> u, u2;
+ matrix<double,0,0,default_memory_manager, column_major_layout> q, q2;
+ matrix<double,N,N,default_memory_manager, column_major_layout> v, v2;
+
+ matrix<double,M,N,MM, column_major_layout> a2;
+ a2 = tmp(a/2);
+
+
+ svd2(true,true,a2+a2,u,q,v);
+
+ double err = max(abs(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v)));
+ DLIB_TEST_MSG( err < 1e-11,"err: " << err);
+ using dlib::equal;
+ DLIB_TEST((equal(trans(u)*u , identity_matrix<double,M>(), 1e-10)));
+ DLIB_TEST((equal(trans(v)*v , identity_matrix<double,N>(), 1e-10)));
+
+ svd2(false,true,a2+a2,u,q,v2);
+ svd2(true,false,a2+a2,u2,q,v);
+ svd2(false,false,a2+a2,u,q2,v);
+
+ err = max(abs(a - subm(u2,get_rect(a2+a2))*diagm(q2)*trans(v2)));
+ DLIB_TEST_MSG( err < 1e-11,"err: " << err);
+ DLIB_TEST((equal(trans(u2)*u2 , identity_matrix<double,M>(), 1e-10)));
+ DLIB_TEST((equal(trans(v2)*v2 , identity_matrix<double,N>(), 1e-10)));
+
+ }
+
+
+
+ {
+ srand(423452);
+ const long M = 10;
+ const long N = 7;
+
+ matrix<double> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double,M,M> u;
+ matrix<double> q;
+ matrix<double,N,N> v;
+
+ matrix<double,M,N,MM> a2;
+ a2 = tmp(a/2);
+
+
+ svd2(true,true,a2+a2,u,q,v);
+
+ double err = sum(round(1e10*(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v))));
+ DLIB_TEST_MSG( err == 0,"err: " << err);
+ DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix<double,M>()));
+ DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix<double,N>()));
+ }
+
+
+ }
+
+
+ void matrix_test2 (
+ )
+ {
+ typedef memory_manager_stateless<char>::kernel_2_2a MM;
+ {
+ srand(423452);
+ const long M = 10;
+ const long N = 7;
+
+ matrix<double> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double,M> u(M,N);
+ matrix<double> w;
+ matrix<double,N,N> v(N,N);
+
+ matrix<double,M,N,MM> a2;
+ a2 = tmp(a/2);
+
+
+ svd(a2+a2,u,w,v);
+
+ DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0);
+ DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix<double,N>()));
+ DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix<double,N>()));
+ }
+
+ {
+ srand(423452);
+ const long M = 1;
+ const long N = 1;
+
+ matrix<double> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double,M,N> u;
+ matrix<double> w;
+ matrix<double,N,N> v;
+
+ matrix<double,M,N> a2;
+ a2 = 0;
+ a2 = tmp(a/2);
+
+
+ svd(a2+a2,u,w,v);
+
+ DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0);
+ DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix<double,N>()));
+ DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix<double,N>()));
+ }
+
+
+ {
+ srand(53434);
+ const long M = 5;
+ const long N = 5;
+
+ matrix<double> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double,0,N> u(M,N);
+ matrix<double,N,N> w;
+ matrix<double> v;
+
+ svd(a,u,w,v);
+
+ DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0);
+ DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix<double,N>()));
+ DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix<double,N>()));
+ }
+
+
+ {
+ srand(11234);
+ const long M = 9;
+ const long N = 4;
+
+ matrix<double,0,0,MM> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double> u;
+ matrix<double,0,0,MM> w;
+ matrix<double> v;
+
+ svd(a,u,w,v);
+
+ DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0);
+ DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix<double,N>()));
+ DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix<double,N>()));
+ }
+
+
+
+ {
+ srand(53934);
+ const long M = 2;
+ const long N = 4;
+
+ matrix<double> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double> u;
+ matrix<double> w;
+ matrix<double> v;
+
+ svd(a,u,w,v);
+
+ DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0);
+ }
+
+
+ {
+ srand(53234);
+ const long M = 9;
+ const long N = 40;
+
+ matrix<double> a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ matrix<double> u;
+ matrix<double> w;
+ matrix<double> v;
+
+ svd(a,u,w,v);
+
+ DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0);
+ }
+
+ {
+ srand(53234);
+ const long M = 9;
+ const long N = 40;
+
+ typedef matrix<double,0,0,default_memory_manager, column_major_layout> mat;
+ mat a(M,N);
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = 10*((double)::rand())/RAND_MAX;
+ }
+ }
+
+ mat u;
+ mat w;
+ mat v;
+
+ svd(a,u,w,v);
+
+ DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0);
+ }
+
+
+ {
+ matrix<double> a(3,3);
+ matrix<double,3,3> b;
+ set_all_elements(a,0);
+
+ a(0,0) = 1;
+ a(1,1) = 2;
+ a(2,2) = 3;
+ b = a;
+
+ DLIB_TEST(diag(a)(0) == 1);
+ DLIB_TEST(diag(a)(1) == 2);
+ DLIB_TEST(diag(a)(2) == 3);
+ DLIB_TEST(diag(a).nr() == 3);
+ DLIB_TEST(diag(a).nc() == 1);
+
+ DLIB_TEST(diag(b)(0) == 1);
+ DLIB_TEST(diag(b)(1) == 2);
+ DLIB_TEST(diag(b)(2) == 3);
+ DLIB_TEST(diag(b).nr() == 3);
+ DLIB_TEST(diag(b).nc() == 1);
+
+ DLIB_TEST(pointwise_multiply(a,b)(0,0) == 1);
+ DLIB_TEST(pointwise_multiply(a,b)(1,1) == 4);
+ DLIB_TEST(pointwise_multiply(a,b)(2,2) == 9);
+ DLIB_TEST(pointwise_multiply(a,b)(1,0) == 0);
+ DLIB_TEST(pointwise_multiply(a,b,a)(1,0) == 0);
+ DLIB_TEST(pointwise_multiply(a,b,a,b)(1,0) == 0);
+
+
+ DLIB_TEST(complex_matrix(a,b)(0,0) == std::complex<double>(1,1));
+ DLIB_TEST(complex_matrix(a,b)(2,2) == std::complex<double>(3,3));
+ DLIB_TEST(complex_matrix(a,b)(2,1) == std::complex<double>(0,0));
+ }
+
+ {
+ matrix<complex<double> > m(2,2), m2(2,2);
+ complex<double> val1(1,2), val2(1.0/complex<double>(1,2));
+ m = val1;
+ m2 = val2;
+
+ DLIB_TEST(equal(reciprocal(m) , m2));
+ }
+ {
+ matrix<complex<float> > m(2,2), m2(2,2);
+ complex<float> val1(1,2), val2(1.0f/complex<float>(1,2));
+ m = val1;
+ m2 = val2;
+
+ DLIB_TEST(equal(reciprocal(m) , m2));
+ }
+
+ {
+ matrix<float,3,1> m1, m2;
+ set_all_elements(m1,2.0);
+ set_all_elements(m2,1.0/2.0);
+ DLIB_TEST(reciprocal(m1) == m2);
+ DLIB_TEST((reciprocal(uniform_matrix<float,3,1>(2.0)) == m2));
+ DLIB_TEST((round_zeros(uniform_matrix<float,3,1>(1e-8f)) == uniform_matrix<float,3,1>(0)) );
+ set_all_elements(m1,2.0);
+ m2 = m1;
+ m1(1,0) = static_cast<float>(1e-8);
+ m2(1,0) = 0;
+ DLIB_TEST(round_zeros(m1) == m2);
+ m1 = round_zeros(m1);
+ DLIB_TEST(m1 == m2);
+ }
+
+ {
+ matrix<matrix<double,2,2> > m;
+ m.set_size(3,3);
+ set_all_elements(m,uniform_matrix<double,2,2>(1));
+ DLIB_TEST((sum(m) == uniform_matrix<double,2,2>(9)));
+ DLIB_TEST((round_zeros(sqrt(sum(m)) - uniform_matrix<double,2,2>(3)) == uniform_matrix<double,2,2>(0)));
+ }
+
+ {
+ matrix<int,2,2> m1;
+ matrix<int> m2;
+ m2.set_size(2,2);
+
+ set_all_elements(m1,2);
+ m2 = uniform_matrix<int,2,2>(2);
+
+ m1 = m1 + m2;
+ DLIB_TEST((m1 == uniform_matrix<int,2,2>(4)));
+
+ set_all_elements(m1,2);
+ set_all_elements(m2,2);
+ m1 = m1*m1;
+ DLIB_TEST((m1 == uniform_matrix<int,2,2>(8)));
+
+ m1(1,0) = 1;
+ set_all_elements(m2,8);
+ m2(0,1) = 1;
+ m1 = trans(m1);
+ DLIB_TEST(m1 == m2);
+ }
+
+ {
+ matrix<double,2,3> m;
+ matrix<double> m2(2,3);
+
+ set_all_elements(m,1);
+ DLIB_TEST(mean(m) == 1);
+ set_all_elements(m,2);
+ DLIB_TEST(mean(m) == 2);
+ m(0,0) = 1;
+ m(0,1) = 1;
+ m(0,2) = 1;
+ DLIB_TEST(abs(mean(m) - 1.5) < 1e-10);
+ DLIB_TEST(abs(variance(m) - 0.3) < 1e-10);
+
+ set_all_elements(m2,1);
+ DLIB_TEST(mean(m2) == 1);
+ set_all_elements(m2,2);
+ DLIB_TEST(mean(m2) == 2);
+ m2(0,0) = 1;
+ m2(0,1) = 1;
+ m2(0,2) = 1;
+ DLIB_TEST(abs(mean(m2) - 1.5) < 1e-10);
+ DLIB_TEST(abs(variance(m2) - 0.3) < 1e-10);
+
+ set_all_elements(m,0);
+ DLIB_TEST(abs(variance(m)) < 1e-10);
+ set_all_elements(m,1);
+ DLIB_TEST(abs(variance(m)) < 1e-10);
+ set_all_elements(m,23.4);
+ DLIB_TEST(abs(variance(m)) < 1e-10);
+ }
+
+ {
+ matrix<matrix<double,3,1,MM>,2,2,MM> m;
+ set_all_elements(m,uniform_matrix<double,3,1>(1));
+ DLIB_TEST((round_zeros(variance(m)) == uniform_matrix<double,3,1>(0)));
+ DLIB_TEST((round_zeros(mean(m)) == uniform_matrix<double,3,1>(1)));
+ m(0,0) = uniform_matrix<double,3,1>(9);
+ DLIB_TEST((round_zeros(variance(m)) == uniform_matrix<double,3,1>(16)));
+ DLIB_TEST((round_zeros(mean(m)) == uniform_matrix<double,3,1>(3)));
+
+ matrix<matrix<double> > m2(2,2);
+ set_all_elements(m2,uniform_matrix<double,3,1>(1));
+ DLIB_TEST((round_zeros(variance(m2)) == uniform_matrix<double,3,1>(0)));
+ DLIB_TEST((round_zeros(mean(m2)) == uniform_matrix<double,3,1>(1)));
+ m2(0,0) = uniform_matrix<double,3,1>(9);
+ DLIB_TEST((round_zeros(variance(m2)) == uniform_matrix<double,3,1>(16)));
+ DLIB_TEST((round_zeros(mean(m2)) == uniform_matrix<double,3,1>(3)));
+ }
+
+
+ {
+ matrix<double> m(4,4), m2;
+ m = 1,2,3,4,
+ 1,2,3,4,
+ 4,6,8,10,
+ 4,6,8,10;
+ m2 = m;
+
+ DLIB_TEST(colm(m,range(0,3)) == m);
+ DLIB_TEST(rowm(m,range(0,3)) == m);
+ DLIB_TEST(colm(m,range(0,0)) == colm(m,0));
+ DLIB_TEST(rowm(m,range(0,0)) == rowm(m,0));
+ DLIB_TEST(colm(m,range(1,1)) == colm(m,1));
+ DLIB_TEST(rowm(m,range(1,1)) == rowm(m,1));
+
+ DLIB_TEST(colm(m,range(2,2)) == colm(m,2));
+ DLIB_TEST(rowm(m,range(2,2)) == rowm(m,2));
+
+ DLIB_TEST(colm(m,range(1,2)) == subm(m,0,1,4,2));
+ DLIB_TEST(rowm(m,range(1,2)) == subm(m,1,0,2,4));
+
+ set_colm(m,range(1,2)) = 9;
+ set_subm(m2,0,1,4,2) = 9;
+ DLIB_TEST(m == m2);
+
+ set_colm(m,range(1,2)) = 11;
+ set_subm(m2,0,1,4,2) = 11;
+ DLIB_TEST(m == m2);
+ }
+
+ {
+ print_spinner();
+ matrix<double,1,1> m1;
+ matrix<double,2,2> m2;
+ matrix<double,3,3> m3;
+ matrix<double,4,4> m4;
+
+ dlib::rand rnd;
+ for (int i = 0; i < 50; ++i)
+ {
+ m1 = randm(1,1,rnd);
+ m2 = randm(2,2,rnd);
+ m3 = randm(3,3,rnd);
+ m4 = randm(4,4,rnd);
+
+ DLIB_TEST(max(abs(m1*inv(m1) - identity_matrix(m1))) < 1e-13);
+ DLIB_TEST(max(abs(m2*inv(m2) - identity_matrix(m2))) < 1e-12);
+ DLIB_TEST(max(abs(m3*inv(m3) - identity_matrix(m3))) < 1e-13);
+ DLIB_TEST_MSG(max(abs(m4*inv(m4) - identity_matrix(m4))) < 1e-12, max(abs(m4*inv(m4) - identity_matrix(m4))));
+ }
+ }
+
+ }
+
+
+
+
+
+
+ class matrix_tester : public tester
+ {
+ public:
+ matrix_tester (
+ ) :
+ tester ("test_matrix2",
+ "Runs tests on the matrix component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ matrix_test1();
+ matrix_test2();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/matrix3.cpp b/ml/dlib/dlib/test/matrix3.cpp
new file mode 100644
index 000000000..b66af638c
--- /dev/null
+++ b/ml/dlib/dlib/test/matrix3.cpp
@@ -0,0 +1,1134 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+
+#include "tester.h"
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/array2d.h>
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.matrix3");
+
+
+ const double eps_mul = 200;
+
+ template <typename T, typename U>
+ void check_equal (
+ const T& a,
+ const U& b
+ )
+ {
+ DLIB_TEST(a.nr() == b.nr());
+ DLIB_TEST(a.nc() == b.nc());
+ typedef typename T::type type;
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ type error = std::abs(a(r,c) - b(r,c));
+ DLIB_TEST_MSG(error < std::sqrt(std::numeric_limits<type>::epsilon())*eps_mul, "error: " << error <<
+ " eps: " << std::sqrt(std::numeric_limits<type>::epsilon())*eps_mul);
+ }
+ }
+ }
+
+ template <typename T, typename U>
+ void c_check_equal (
+ const T& a,
+ const U& b
+ )
+ {
+ DLIB_TEST(a.nr() == b.nr());
+ DLIB_TEST(a.nc() == b.nc());
+ typedef typename T::type type;
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ typename type::value_type error = std::abs(a(r,c) - b(r,c));
+ DLIB_TEST_MSG(error < std::sqrt(std::numeric_limits<typename type::value_type>::epsilon())*eps_mul, "error: " << error <<
+ " eps: " << std::sqrt(std::numeric_limits<typename type::value_type>::epsilon())*eps_mul);
+ }
+ }
+ }
+
+ template <typename T, typename U>
+ void assign_no_blas (
+ const T& a_,
+ const U& b
+ )
+ {
+ T& a = const_cast<T&>(a_);
+ DLIB_TEST(a.nr() == b.nr());
+ DLIB_TEST(a.nc() == b.nc());
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = b(r,c);
+ }
+ }
+ }
+
+ template <typename type>
+ type rnd_num (dlib::rand& rnd)
+ {
+ return static_cast<type>(10*rnd.get_random_double());
+ }
+
+ template <typename type>
+ void test_blas( long rows, long cols)
+ {
+ // The tests in this function exercise the BLAS bindings located in the matrix/matrix_blas_bindings.h file.
+ // It does this by performing an assignment that is subject to BLAS bindings and comparing the
+ // results directly to an unevaluated matrix_exp that should be equal.
+
+ dlib::rand rnd;
+
+ matrix<type> a(rows,cols), temp, temp2, temp3;
+
+ for (int k = 0; k < 6; ++k)
+ {
+ for (long r= 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a(r,c) = rnd_num<type>(rnd);
+ }
+ }
+ matrix<type> at;
+ at = trans(a);
+
+ matrix<complex<type> > c_a(rows,cols), c_at, c_sqr;
+ for (long r= 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ c_a(r,c) = complex<type>(rnd_num<type>(rnd),rnd_num<type>(rnd));
+ }
+ }
+ c_at = trans(c_a);
+ const int size = max(rows,cols);
+ c_sqr = 10*matrix_cast<complex<type> >(complex_matrix(randm(size,size,rnd), randm(size,size,rnd)));
+
+
+ matrix<complex<type> > c_temp(cols,cols), c_temp2(cols,cols);
+ const complex<type> i(0,1);
+
+ const type one = 1;
+ const type two = 1;
+ const type num1 = static_cast<type>(3.6);
+ const type num2 = static_cast<type>(6.6);
+ const type num3 = static_cast<type>(8.6);
+
+ matrix<complex<type>,0,1> c_cv4(cols), c_cv3(rows);
+ matrix<complex<type>,1,0> c_rv4(cols), c_rv3(rows);
+
+ matrix<type,0,1> cv4(cols);
+
+ for (long idx = 0; idx < cv4.size(); ++idx)
+ cv4(idx) = rnd_num<type>(rnd);
+
+ for (long idx = 0; idx < c_cv4.size(); ++idx)
+ c_cv4(idx) = complex<type>(rnd_num<type>(rnd),rnd_num<type>(rnd));
+
+ matrix<type,1,0> rv3(rows);
+
+ for (long idx = 0; idx < rv3.size(); ++idx)
+ rv3(idx) = rnd_num<type>(rnd);
+
+ for (long idx = 0; idx < c_rv3.size(); ++idx)
+ c_rv3(idx) = complex<type>(rnd_num<type>(rnd),rnd_num<type>(rnd));
+
+ matrix<type,0,1> cv3(rows);
+
+ for (long idx = 0; idx < cv3.size(); ++idx)
+ cv3(idx) = rnd_num<type>(rnd);
+
+ for (long idx = 0; idx < c_cv3.size(); ++idx)
+ c_cv3(idx) = complex<type>(rnd_num<type>(rnd),rnd_num<type>(rnd));
+
+ matrix<type,1,0> rv4(cols);
+ for (long idx = 0; idx < rv4.size(); ++idx)
+ rv4(idx) = rnd_num<type>(rnd);
+
+ for (long idx = 0; idx < c_rv4.size(); ++idx)
+ c_rv4(idx) = complex<type>(rnd_num<type>(rnd),rnd_num<type>(rnd));
+
+
+
+ // GEMM tests
+ dlog << LTRACE << "1.1";
+ check_equal(tmp(at*a), at*a);
+ check_equal(tmp(trans(at*a)), trans(at*a));
+ check_equal(tmp(2.4*trans(4*trans(at*a) + at*3*a)), 2.4*trans(4*trans(at*a) + at*3*a));
+ dlog << LTRACE << "1.2";
+ check_equal(tmp(trans(a)*a), trans(a)*a);
+ check_equal(tmp(trans(trans(a)*a)), trans(trans(a)*a));
+ dlog << LTRACE << "1.3";
+ check_equal(tmp(at*trans(at)), at*trans(at));
+ check_equal(tmp(trans(at*trans(at))), trans(at*trans(at)));
+ dlog << LTRACE << "1.4";
+ check_equal(tmp(trans(at)*trans(a)), a*at);
+ check_equal(tmp(trans(trans(at)*trans(a))), trans(a*at));
+ dlog << LTRACE << "1.5";
+
+ print_spinner();
+ c_check_equal(tmp(conj(trans(c_a))*c_a), trans(conj(c_a))*c_a);
+ dlog << LTRACE << "1.5.1";
+ c_check_equal(tmp(trans(conj(trans(c_a))*c_a)), trans(trans(conj(c_a))*c_a));
+ dlog << LTRACE << "1.5.2";
+ c_check_equal(tmp((conj(trans(c_sqr))*trans(c_sqr))), (trans(conj(c_sqr))*trans(c_sqr)));
+ dlog << LTRACE << "1.5.3";
+ c_check_equal(tmp(trans(conj(trans(c_sqr))*trans(c_sqr))), trans(trans(conj(c_sqr))*trans(c_sqr)));
+ dlog << LTRACE << "1.6";
+ c_check_equal(tmp(c_at*trans(conj(c_at))), c_at*conj(trans(c_at)));
+ dlog << LTRACE << "1.6.1";
+ c_check_equal(tmp(trans(c_at*trans(conj(c_at)))), trans(c_at*conj(trans(c_at))));
+ dlog << LTRACE << "1.6.2";
+ c_check_equal(tmp((c_sqr)*trans(conj(c_sqr))), (c_sqr)*conj(trans(c_sqr)));
+ dlog << LTRACE << "1.6.2.1";
+ c_check_equal(tmp(trans(c_sqr)*trans(conj(c_sqr))), trans(c_sqr)*conj(trans(c_sqr)));
+ dlog << LTRACE << "1.6.3";
+ c_check_equal(tmp(trans(trans(c_sqr)*trans(conj(c_sqr)))), trans(trans(c_sqr)*conj(trans(c_sqr))));
+ dlog << LTRACE << "1.7";
+ c_check_equal(tmp(conj(trans(c_at))*trans(conj(c_a))), conj(trans(c_at))*trans(conj(c_a)));
+ c_check_equal(tmp(trans(conj(trans(c_at))*trans(conj(c_a)))), trans(conj(trans(c_at))*trans(conj(c_a))));
+ dlog << LTRACE << "1.8";
+
+ check_equal(tmp(a*trans(rowm(a,1))) , a*trans(rowm(a,1)));
+ check_equal(tmp(a*colm(at,1)) , a*colm(at,1));
+ check_equal(tmp(subm(a,1,1,2,2)*subm(a,1,2,2,2)), subm(a,1,1,2,2)*subm(a,1,2,2,2));
+
+ dlog << LTRACE << "1.9";
+ check_equal(tmp(trans(a*trans(rowm(a,1)))) , trans(a*trans(rowm(a,1))));
+ dlog << LTRACE << "1.10";
+ check_equal(tmp(trans(a*colm(at,1))) , trans(a*colm(at,1)));
+ dlog << LTRACE << "1.11";
+ check_equal(tmp(trans(subm(a,1,1,2,2)*subm(a,1,2,2,2))), trans(subm(a,1,1,2,2)*subm(a,1,2,2,2)));
+ dlog << LTRACE << "1.12";
+
+ {
+ temp = at*a;
+ temp2 = temp;
+
+ temp += 3.5*at*a;
+ assign_no_blas(temp2, temp2 + 3.5*at*a);
+ check_equal(temp, temp2);
+
+ temp -= at*3.5*a;
+ assign_no_blas(temp2, temp2 - at*3.5*a);
+ check_equal(temp, temp2);
+
+ temp = temp + 4*at*a;
+ assign_no_blas(temp2, temp2 + 4*at*a);
+ check_equal(temp, temp2);
+
+ temp = temp - 2.4*at*a;
+ assign_no_blas(temp2, temp2 - 2.4*at*a);
+ check_equal(temp, temp2);
+ }
+ dlog << LTRACE << "1.13";
+ {
+ temp = trans(at*a);
+ temp2 = temp;
+ temp3 = temp;
+
+ dlog << LTRACE << "1.14";
+ temp += trans(3.5*at*a);
+ assign_no_blas(temp2, temp2 + trans(3.5*at*a));
+ check_equal(temp, temp2);
+
+ dlog << LTRACE << "1.15";
+ temp -= trans(at*3.5*a);
+ assign_no_blas(temp2, temp2 - trans(at*3.5*a));
+ check_equal(temp, temp2);
+
+ dlog << LTRACE << "1.16";
+ temp = trans(temp + 4*at*a);
+ assign_no_blas(temp3, trans(temp2 + 4*at*a));
+ check_equal(temp, temp3);
+
+ temp2 = temp;
+ dlog << LTRACE << "1.17";
+ temp = trans(temp - 2.4*at*a);
+ assign_no_blas(temp3, trans(temp2 - 2.4*at*a));
+ check_equal(temp, temp3);
+ }
+
+ dlog << LTRACE << "1.17.1";
+ {
+ matrix<type> m1, m2;
+
+ m1 = matrix_cast<type>(randm(rows, cols, rnd));
+ m2 = matrix_cast<type>(randm(cols, rows + 8, rnd));
+ check_equal(tmp(m1*m2), m1*m2);
+ check_equal(tmp(trans(m1*m2)), trans(m1*m2));
+
+ m1 = trans(m1);
+ check_equal(tmp(trans(m1)*m2), trans(m1)*m2);
+ check_equal(tmp(trans(trans(m1)*m2)), trans(trans(m1)*m2));
+
+ m2 = trans(m2);
+ check_equal(tmp(trans(m1)*trans(m2)), trans(m1)*trans(m2));
+ check_equal(tmp(trans(trans(m1)*trans(m2))), trans(trans(m1)*trans(m2)));
+
+ m1 = trans(m1);
+ check_equal(tmp(m1*trans(m2)), m1*trans(m2));
+ check_equal(tmp(trans(m1*trans(m2))), trans(m1*trans(m2)));
+ }
+
+ dlog << LTRACE << "1.17.5";
+ {
+ matrix<type,1,0> r;
+ matrix<type,0,1> c;
+
+ r = matrix_cast<type>(randm(1, rows+9, rnd));
+ c = matrix_cast<type>(randm(rows, 1, rnd));
+
+ check_equal(tmp(c*r), c*r);
+ check_equal(tmp(trans(c*r)), trans(c*r));
+
+ check_equal(tmp(trans(r)*trans(c)), trans(r)*trans(c));
+ check_equal(tmp(trans(trans(r)*trans(c))), trans(trans(r)*trans(c)));
+ }
+
+ dlog << LTRACE << "1.18";
+
+ // GEMV tests
+ check_equal(tmp(a*cv4), a*cv4);
+ check_equal(tmp(trans(a*cv4)), trans(a*cv4));
+ check_equal(tmp(rv3*a), rv3*a);
+ check_equal(tmp(trans(cv4)*at), trans(cv4)*at);
+ check_equal(tmp(a*trans(rv4)), a*trans(rv4));
+ check_equal(tmp(trans(a*trans(rv4))), trans(a*trans(rv4)));
+
+ check_equal(tmp(trans(a)*cv3), trans(a)*cv3);
+ check_equal(tmp(rv4*trans(a)), rv4*trans(a));
+ check_equal(tmp(trans(cv3)*trans(at)), trans(cv3)*trans(at));
+ check_equal(tmp(trans(cv3)*a), trans(cv3)*a);
+ check_equal(tmp(trans(a)*trans(rv3)), trans(a)*trans(rv3));
+
+
+ c_check_equal(tmp(trans(conj(c_a))*c_cv3), trans(conj(c_a))*c_cv3);
+ c_check_equal(tmp(c_rv4*trans(conj(c_a))), c_rv4*trans(conj(c_a)));
+ c_check_equal(tmp(trans(c_cv3)*trans(conj(c_at))), trans(c_cv3)*trans(conj(c_at)));
+ c_check_equal(tmp(conj(trans(c_a))*trans(c_rv3)), trans(conj(c_a))*trans(c_rv3));
+ c_check_equal(tmp(c_rv4*conj(c_at)), c_rv4*conj(c_at));
+ c_check_equal(tmp(trans(c_cv4)*conj(c_at)), trans(c_cv4)*conj(c_at));
+
+ dlog << LTRACE << "2.00";
+
+ c_check_equal(tmp(trans(trans(conj(c_a))*c_cv3)), trans(trans(conj(c_a))*c_cv3));
+ c_check_equal(tmp(trans(c_rv4*trans(conj(c_a)))), trans(c_rv4*trans(conj(c_a))));
+ c_check_equal(tmp(trans(trans(c_cv3)*trans(conj(c_at)))), trans(trans(c_cv3)*trans(conj(c_at))));
+ dlog << LTRACE << "2.20";
+ c_check_equal(tmp(trans(conj(trans(c_a))*trans(c_rv3))), trans(trans(conj(c_a))*trans(c_rv3)));
+ c_check_equal(tmp(trans(c_rv4*conj(c_at))), trans(c_rv4*conj(c_at)));
+ c_check_equal(tmp(trans(trans(c_cv4)*conj(c_at))), trans(trans(c_cv4)*conj(c_at)));
+
+
+
+ dlog << LTRACE << "6";
+ temp = a*at;
+ check_equal(temp, a*at);
+ temp = temp + a*at + trans(at)*at + trans(at)*sin(at);
+ check_equal(temp, a*at + a*at+ trans(at)*at + trans(at)*sin(at));
+
+ dlog << LTRACE << "6.1";
+ temp = a*at;
+ check_equal(temp, a*at);
+ temp = a*at + temp;
+ check_equal(temp, a*at + a*at);
+
+ print_spinner();
+ dlog << LTRACE << "6.2";
+ temp = a*at;
+ check_equal(temp, a*at);
+ dlog << LTRACE << "6.2.3";
+ temp = temp - a*at;
+ dlog << LTRACE << "6.2.4";
+ check_equal(temp, a*at-a*at);
+
+ dlog << LTRACE << "6.3";
+ temp = a*at;
+ dlog << LTRACE << "6.3.5";
+ check_equal(temp, a*at);
+ dlog << LTRACE << "6.3.6";
+ temp = a*at - temp;
+ dlog << LTRACE << "6.4";
+ check_equal(temp, a*at-a*at);
+
+
+
+ const long d = min(rows,cols);
+ rectangle rect(1,1,d,d);
+ temp.set_size(max(rows,cols)+4,max(rows,cols)+4);
+ set_all_elements(temp,4);
+ temp2 = temp;
+
+ dlog << LTRACE << "7";
+ set_subm(temp,rect) = a*at;
+ assign_no_blas( set_subm(temp2,rect) , a*at);
+ check_equal(temp, temp2);
+
+ temp = a;
+ temp2 = a;
+
+ set_colm(temp,1) = a*cv4;
+ assign_no_blas( set_colm(temp2,1) , a*cv4);
+ check_equal(temp, temp2);
+
+ set_rowm(temp,1) = rv3*a;
+ assign_no_blas( set_rowm(temp2,1) , rv3*a);
+ check_equal(temp, temp2);
+
+
+ // Test BLAS GER
+ {
+ temp.set_size(cols,cols);
+ set_all_elements(temp,3);
+ temp2 = temp;
+
+
+ dlog << LTRACE << "8";
+ temp += cv4*rv4;
+ assign_no_blas(temp2, temp2 + cv4*rv4);
+ check_equal(temp, temp2);
+
+ dlog << LTRACE << "8.3";
+ temp = temp + cv4*rv4;
+ assign_no_blas(temp2, temp2 + cv4*rv4);
+ check_equal(temp, temp2);
+ dlog << LTRACE << "8.9";
+ }
+ {
+ temp.set_size(cols,cols);
+ set_all_elements(temp,3);
+ temp2 = temp;
+ temp3 = 0;
+
+ dlog << LTRACE << "8.10";
+
+ temp += trans(cv4*rv4);
+ assign_no_blas(temp3, temp2 + trans(cv4*rv4));
+ check_equal(temp, temp3);
+ temp3 = 0;
+
+ dlog << LTRACE << "8.11";
+ temp2 = temp;
+ temp = trans(temp + cv4*rv4);
+ assign_no_blas(temp3, trans(temp2 + cv4*rv4));
+ check_equal(temp, temp3);
+ dlog << LTRACE << "8.12";
+ }
+ {
+ matrix<complex<type> > temp, temp2, temp3;
+ matrix<complex<type>,0,1 > cv4;
+ matrix<complex<type>,1,0 > rv4;
+ cv4.set_size(cols);
+ rv4.set_size(cols);
+ temp.set_size(cols,cols);
+ set_all_elements(temp,complex<type>(3,5));
+ temp(cols-1, cols-4) = 9;
+ temp2 = temp;
+ temp3.set_size(cols,cols);
+ temp3 = 0;
+
+ for (long i = 0; i < rv4.size(); ++i)
+ {
+ rv4(i) = complex<type>(rnd_num<type>(rnd),rnd_num<type>(rnd));
+ cv4(i) = complex<type>(rnd_num<type>(rnd),rnd_num<type>(rnd));
+ }
+
+ dlog << LTRACE << "8.13";
+
+ temp += trans(cv4*rv4);
+ assign_no_blas(temp3, temp2 + trans(cv4*rv4));
+ c_check_equal(temp, temp3);
+ temp3 = 0;
+
+ dlog << LTRACE << "8.14";
+ temp2 = temp;
+ temp = trans(temp + cv4*rv4);
+ assign_no_blas(temp3, trans(temp2 + cv4*rv4));
+ c_check_equal(temp, temp3);
+ dlog << LTRACE << "8.15";
+ }
+
+
+
+
+ set_all_elements(c_temp, one + num1*i);
+ c_temp2 = c_temp;
+ set_all_elements(c_rv4, one + num2*i);
+ set_all_elements(c_cv4, two + num3*i);
+
+
+ dlog << LTRACE << "9";
+ c_temp += c_cv4*c_rv4;
+ assign_no_blas(c_temp2, c_temp2 + c_cv4*c_rv4);
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "9.1";
+ c_temp += c_cv4*conj(c_rv4);
+ assign_no_blas(c_temp2, c_temp2 + c_cv4*conj(c_rv4));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "9.2";
+ c_temp = c_cv4*conj(c_rv4) + c_temp;
+ assign_no_blas(c_temp2, c_temp2 + c_cv4*conj(c_rv4));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "9.3";
+ c_temp = trans(c_rv4)*trans(conj(c_cv4)) + c_temp;
+ assign_no_blas(c_temp2, c_temp2 + trans(c_rv4)*trans(conj(c_cv4)));
+ c_check_equal(c_temp, c_temp2);
+
+
+ dlog << LTRACE << "9.4";
+ c_temp += conj(c_cv4)*c_rv4;
+ assign_no_blas(c_temp2, c_temp2 + conj(c_cv4)*c_rv4);
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "9.5";
+ c_temp += conj(c_cv4)*conj(c_rv4);
+ assign_no_blas(c_temp2, c_temp2 + conj(c_cv4)*conj(c_rv4));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "9.6";
+ c_temp = conj(c_cv4)*conj(c_rv4) + c_temp;
+ assign_no_blas(c_temp2, c_temp2 + conj(c_cv4)*conj(c_rv4));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "9.7";
+ c_temp = conj(trans(c_rv4))*trans(conj(c_cv4)) + c_temp;
+ assign_no_blas(c_temp2, c_temp2 + conj(trans(c_rv4))*trans(conj(c_cv4)));
+ c_check_equal(c_temp, c_temp2);
+
+
+ dlog << LTRACE << "10";
+ c_temp += trans(c_cv4*c_rv4);
+ assign_no_blas(c_temp2, c_temp2 + trans(c_cv4*c_rv4));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "10.1";
+ c_temp += trans(c_cv4*conj(c_rv4));
+ assign_no_blas(c_temp2, c_temp2 + trans(c_cv4*conj(c_rv4)));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "10.2";
+ c_temp = trans(c_cv4*conj(c_rv4)) + c_temp;
+ assign_no_blas(c_temp2, c_temp2 + trans(c_cv4*conj(c_rv4)));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "10.3";
+ c_temp = trans(trans(c_rv4)*trans(conj(c_cv4))) + c_temp;
+ assign_no_blas(c_temp2, c_temp2 + trans(trans(c_rv4)*trans(conj(c_cv4))));
+ c_check_equal(c_temp, c_temp2);
+
+
+ dlog << LTRACE << "10.4";
+ c_temp += trans(conj(c_cv4)*c_rv4);
+ assign_no_blas(c_temp2, c_temp2 + trans(conj(c_cv4)*c_rv4));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "10.5";
+ c_temp += trans(conj(c_cv4)*conj(c_rv4));
+ assign_no_blas(c_temp2, c_temp2 + trans(conj(c_cv4)*conj(c_rv4)));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "10.6";
+ c_temp = trans(conj(c_cv4)*conj(c_rv4)) + c_temp;
+ assign_no_blas(c_temp2, c_temp2 + trans(conj(c_cv4)*conj(c_rv4)));
+ c_check_equal(c_temp, c_temp2);
+ dlog << LTRACE << "10.7";
+ c_temp = trans(conj(trans(c_rv4))*trans(conj(c_cv4))) + c_temp;
+ assign_no_blas(c_temp2, c_temp2 + trans(conj(trans(c_rv4))*trans(conj(c_cv4))));
+ c_check_equal(c_temp, c_temp2);
+
+ dlog << LTRACE << "10.8";
+
+
+ print_spinner();
+
+ // Test DOT
+ check_equal( tmp(rv4*cv4), rv4*cv4);
+ check_equal( tmp(trans(rv4*cv4)), trans(rv4*cv4));
+ check_equal( tmp(trans(cv4)*trans(rv4)), trans(cv4)*trans(rv4));
+ check_equal( tmp(rv4*3.9*cv4), rv4*3.9*cv4);
+ check_equal( tmp(trans(cv4)*3.9*trans(rv4)), trans(cv4)*3.9*trans(rv4));
+ check_equal( tmp(rv4*cv4*3.9), rv4*3.9*cv4);
+ check_equal( tmp(trans(cv4)*trans(rv4)*3.9), trans(cv4)*3.9*trans(rv4));
+
+
+ check_equal( tmp(trans(rv4*cv4)), trans(rv4*cv4));
+ check_equal( tmp(trans(trans(rv4*cv4))), trans(trans(rv4*cv4)));
+ check_equal( tmp(trans(trans(cv4)*trans(rv4))), trans(trans(cv4)*trans(rv4)));
+ check_equal( tmp(trans(rv4*3.9*cv4)), trans(rv4*3.9*cv4));
+ check_equal( tmp(trans(trans(cv4)*3.9*trans(rv4))), trans(trans(cv4)*3.9*trans(rv4)));
+ check_equal( tmp(trans(rv4*cv4*3.9)), trans(rv4*3.9*cv4));
+ check_equal( tmp(trans(trans(cv4)*trans(rv4)*3.9)), trans(trans(cv4)*3.9*trans(rv4)));
+
+
+ temp.set_size(1,1);
+ temp = 4;
+ check_equal( tmp(temp + rv4*cv4), temp + rv4*cv4);
+ check_equal( tmp(temp + trans(cv4)*trans(rv4)), temp + trans(cv4)*trans(rv4));
+
+ dlog << LTRACE << "11";
+
+
+
+ c_check_equal( tmp(conj(c_rv4)*c_cv4), conj(c_rv4)*c_cv4);
+ c_check_equal( tmp(conj(trans(c_cv4))*trans(c_rv4)), trans(conj(c_cv4))*trans(c_rv4));
+
+ c_check_equal( tmp(conj(c_rv4)*i*c_cv4), conj(c_rv4)*i*c_cv4);
+ c_check_equal( tmp(conj(trans(c_cv4))*i*trans(c_rv4)), trans(conj(c_cv4))*i*trans(c_rv4));
+
+ c_temp.set_size(1,1);
+ c_temp = 4;
+ c_check_equal( tmp(c_temp + conj(c_rv4)*c_cv4), c_temp + conj(c_rv4)*c_cv4);
+ c_check_equal( tmp(c_temp + trans(conj(c_cv4))*trans(c_rv4)), c_temp + trans(conj(c_cv4))*trans(c_rv4));
+
+ complex<type> tmp = c_rv4*c_cv4;
+ DLIB_TEST(abs((tmp + i) - ((c_rv4*c_cv4)(0) + i)) < std::sqrt(std::numeric_limits<type>::epsilon())*eps_mul );
+ DLIB_TEST(max(abs((rv4*cv4 + 1.0) - ((rv4*cv4)(0) + 1.0))) < std::sqrt(std::numeric_limits<type>::epsilon())*eps_mul);
+
+ }
+
+ {
+ matrix<int> m(2,3), m2(6,1);
+
+ m = 1,2,3,
+ 4,5,6;
+
+ m2 = 1,2,3,4,5,6;
+
+ DLIB_TEST(reshape_to_column_vector(m) == m2);
+ DLIB_TEST(reshape_to_column_vector(m+m) == m2+m2);
+
+ }
+ {
+ matrix<int,2,3> m(2,3);
+ matrix<int> m2(6,1);
+
+ m = 1,2,3,
+ 4,5,6;
+
+ m2 = 1,2,3,4,5,6;
+
+ DLIB_TEST(reshape_to_column_vector(m) == m2);
+ DLIB_TEST(reshape_to_column_vector(m+m) == m2+m2);
+
+ }
+ }
+
+
+ void matrix_test (
+ )
+ /*!
+ ensures
+ - runs tests on the matrix stuff compliance with the specs
+ !*/
+ {
+ print_spinner();
+
+
+ {
+ matrix<long> m1(2,2), m2(2,2);
+
+ m1 = 1, 2,
+ 3, 4;
+
+ m2 = 4, 5,
+ 6, 7;
+
+
+ DLIB_TEST(subm(tensor_product(m1,m2),range(0,1), range(0,1)) == 1*m2);
+ DLIB_TEST(subm(tensor_product(m1,m2),range(0,1), range(2,3)) == 2*m2);
+ DLIB_TEST(subm(tensor_product(m1,m2),range(2,3), range(0,1)) == 3*m2);
+ DLIB_TEST(subm(tensor_product(m1,m2),range(2,3), range(2,3)) == 4*m2);
+ }
+
+ {
+ print_spinner();
+ dlog << LTRACE << "testing blas stuff";
+ dlog << LTRACE << " \nsmall double";
+ test_blas<double>(3,4);
+ print_spinner();
+ dlog << LTRACE << " \nsmall float";
+ test_blas<float>(3,4);
+ print_spinner();
+ dlog << LTRACE << " \nbig double";
+ test_blas<double>(120,131);
+ print_spinner();
+ dlog << LTRACE << " \nbig float";
+ test_blas<float>(120,131);
+ print_spinner();
+ dlog << LTRACE << "testing done";
+ }
+
+
+ {
+ matrix<long> m(3,4), ml(3,4), mu(3,4);
+ m = 1,2,3,4,
+ 4,5,6,7,
+ 7,8,9,0;
+
+ ml = 1,0,0,0,
+ 4,5,0,0,
+ 7,8,9,0;
+
+ mu = 1,2,3,4,
+ 0,5,6,7,
+ 0,0,9,0;
+
+
+ DLIB_TEST(lowerm(m) == ml);
+ DLIB_TEST(upperm(m) == mu);
+
+ ml = 3,0,0,0,
+ 4,3,0,0,
+ 7,8,3,0;
+
+ mu = 4,2,3,4,
+ 0,4,6,7,
+ 0,0,4,0;
+
+ DLIB_TEST(lowerm(m,3) == ml);
+ DLIB_TEST(upperm(m,4) == mu);
+
+ }
+
+ {
+ matrix<long> m(3,4), row(1,3), col(2,1);
+ m = 1,2,3,4,
+ 4,5,6,7,
+ 7,8,9,0;
+
+ row = 4,5,6;
+ col = 3,6;
+
+ DLIB_TEST(rowm(m, 1, 3) == row);
+ DLIB_TEST(colm(m, 2, 2) == col);
+
+ }
+
+
+ {
+ std::vector<double> v(34, 8);
+ std::vector<double> v2(34, 9);
+
+ DLIB_TEST(mat(&v[0], v.size()) == mat(v));
+ DLIB_TEST(mat(&v2[0], v.size()) != mat(v));
+ }
+
+ {
+ std::vector<long> v(1, 3);
+ std::vector<long> v2(1, 2);
+
+ DLIB_TEST(mat(&v[0], v.size()) == mat(v));
+ DLIB_TEST(mat(&v2[0], v.size()) != mat(v));
+ }
+
+ {
+ matrix<double> a(3,3), b(3,3);
+ a = 1, 2.5, 1,
+ 3, 4, 5,
+ 0.5, 2.2, 3;
+
+ b = 0, 1, 0,
+ 1, 1, 1,
+ 0, 1, 1;
+
+ DLIB_TEST((a>1) == b);
+ DLIB_TEST((1<a) == b);
+
+ b = 1, 1, 1,
+ 1, 1, 1,
+ 0, 1, 1;
+
+ DLIB_TEST((a>=1) == b);
+ DLIB_TEST((1<=a) == b);
+
+ b = 0, 0, 0,
+ 0, 0, 0,
+ 0, 1, 0;
+ DLIB_TEST((a==2.2) == b);
+ DLIB_TEST((a!=2.2) == (b==0));
+ DLIB_TEST((2.2==a) == b);
+ DLIB_TEST((2.2!=a) == (0==b));
+
+ b = 0, 0, 0,
+ 0, 0, 0,
+ 1, 0, 0;
+ DLIB_TEST((a<1) == b);
+ DLIB_TEST((1>a) == b);
+
+ b = 1, 0, 1,
+ 0, 0, 0,
+ 1, 0, 0;
+ DLIB_TEST((a<=1) == b);
+ DLIB_TEST((1>=a) == b);
+ }
+
+ {
+ matrix<double> a, b, c;
+ a = randm(4,2);
+
+ b += a;
+ c -= a;
+
+ DLIB_TEST(equal(a, b));
+ DLIB_TEST(equal(-a, c));
+
+ b += a;
+ c -= a;
+
+ DLIB_TEST(equal(2*a, b));
+ DLIB_TEST(equal(-2*a, c));
+
+ b += a + a;
+ c -= a + a;
+
+ DLIB_TEST(equal(4*a, b));
+ DLIB_TEST(equal(-4*a, c));
+
+ b.set_size(0,0);
+ c.set_size(0,0);
+
+
+ b += a + a;
+ c -= a + a;
+
+ DLIB_TEST(equal(2*a, b));
+ DLIB_TEST(equal(-2*a, c));
+ }
+
+ {
+ matrix<int> a, b, c;
+
+ a.set_size(2, 3);
+ b.set_size(2, 6);
+ c.set_size(4, 3);
+
+ a = 1, 2, 3,
+ 4, 5, 6;
+
+ b = 1, 2, 3, 1, 2, 3,
+ 4, 5, 6, 4, 5, 6;
+
+ c = 1, 2, 3,
+ 4, 5, 6,
+ 1, 2, 3,
+ 4, 5, 6;
+
+ DLIB_TEST(join_rows(a,a) == b);
+ DLIB_TEST(join_rows(a,abs(a)) == b);
+ DLIB_TEST(join_cols(trans(a), trans(a)) == trans(b));
+ DLIB_TEST(join_cols(a,a) == c);
+ DLIB_TEST(join_cols(a,abs(a)) == c);
+ DLIB_TEST(join_rows(trans(a),trans(a)) == trans(c));
+ }
+
+ {
+ matrix<int, 2, 3> a;
+ matrix<int, 2, 6> b;
+ matrix<int, 4, 3> c;
+
+ a = 1, 2, 3,
+ 4, 5, 6;
+
+ b = 1, 2, 3, 1, 2, 3,
+ 4, 5, 6, 4, 5, 6;
+
+ c = 1, 2, 3,
+ 4, 5, 6,
+ 1, 2, 3,
+ 4, 5, 6;
+
+ DLIB_TEST(join_rows(a,a) == b);
+ DLIB_TEST(join_rows(a,abs(a)) == b);
+ DLIB_TEST(join_cols(trans(a), trans(a)) == trans(b));
+ DLIB_TEST(join_cols(a,a) == c);
+ DLIB_TEST(join_cols(a,abs(a)) == c);
+ DLIB_TEST(join_rows(trans(a),trans(a)) == trans(c));
+ }
+
+ {
+ matrix<int, 2, 3> a;
+ matrix<int> a2;
+ matrix<int, 2, 6> b;
+ matrix<int, 4, 3> c;
+
+ a = 1, 2, 3,
+ 4, 5, 6;
+
+ a2 = a;
+
+ b = 1, 2, 3, 1, 2, 3,
+ 4, 5, 6, 4, 5, 6;
+
+ c = 1, 2, 3,
+ 4, 5, 6,
+ 1, 2, 3,
+ 4, 5, 6;
+
+ DLIB_TEST(join_rows(a,a2) == b);
+ DLIB_TEST(join_rows(a2,a) == b);
+ DLIB_TEST(join_cols(trans(a2), trans(a)) == trans(b));
+ DLIB_TEST(join_cols(a2,a) == c);
+ DLIB_TEST(join_cols(a,a2) == c);
+ DLIB_TEST(join_rows(trans(a2),trans(a)) == trans(c));
+ }
+
+ {
+ matrix<int> a, b;
+
+ a.set_size(2,3);
+
+ a = 1, 2, 3,
+ 4, 5, 6;
+
+ b.set_size(3,2);
+ b = 1, 2,
+ 3, 4,
+ 5, 6;
+
+ DLIB_TEST(reshape(a, 3, 2) == b);
+
+ b.set_size(2,3);
+ b = 1, 4, 2,
+ 5, 3, 6;
+
+ DLIB_TEST(reshape(trans(a), 2, 3) == b);
+
+ }
+
+ {
+ matrix<int,2,3> a;
+ matrix<int> b;
+
+ a = 1, 2, 3,
+ 4, 5, 6;
+
+ b.set_size(3,2);
+ b = 1, 2,
+ 3, 4,
+ 5, 6;
+
+ DLIB_TEST(reshape(a, 3, 2) == b);
+
+ b.set_size(2,3);
+ b = 1, 4, 2,
+ 5, 3, 6;
+
+ DLIB_TEST(reshape(trans(a), 2, 3) == b);
+
+ }
+
+ {
+ std::vector<int> v(6);
+ for (unsigned long i = 0; i < v.size(); ++i)
+ v[i] = i;
+
+ matrix<int,2,3> a;
+ a = 0, 1, 2,
+ 3, 4, 5;
+
+ DLIB_TEST(mat(&v[0], 2, 3) == a);
+ }
+
+ {
+ matrix<int> a(3,4);
+ matrix<int> b(3,1), c(1,4);
+
+ a = 1, 2, 3, 6,
+ 4, 5, 6, 9,
+ 1, 1, 1, 3;
+
+ b(0) = sum(rowm(a,0));
+ b(1) = sum(rowm(a,1));
+ b(2) = sum(rowm(a,2));
+
+ c(0) = sum(colm(a,0));
+ c(1) = sum(colm(a,1));
+ c(2) = sum(colm(a,2));
+ c(3) = sum(colm(a,3));
+
+ DLIB_TEST(sum_cols(a) == b);
+ DLIB_TEST(sum_rows(a) == c);
+
+ }
+
+ {
+ matrix<int> m(3,3);
+
+ m = 1, 2, 3,
+ 4, 5, 6,
+ 7, 8, 9;
+
+ DLIB_TEST(make_symmetric(m) == trans(make_symmetric(m)));
+ DLIB_TEST(lowerm(make_symmetric(m)) == lowerm(m));
+ DLIB_TEST(upperm(make_symmetric(m)) == trans(lowerm(m)));
+ }
+
+ {
+ matrix<int,3,4> a;
+ matrix<int> b(3,1), c(1,4);
+
+ a = 1, 2, 3, 6,
+ 4, 5, 6, 9,
+ 1, 1, 1, 3;
+
+ b(0) = sum(rowm(a,0));
+ b(1) = sum(rowm(a,1));
+ b(2) = sum(rowm(a,2));
+
+ c(0) = sum(colm(a,0));
+ c(1) = sum(colm(a,1));
+ c(2) = sum(colm(a,2));
+ c(3) = sum(colm(a,3));
+
+ DLIB_TEST(sum_cols(a) == b);
+ DLIB_TEST(sum_rows(a) == c);
+
+ }
+
+ {
+ matrix<int> m(3,4), s(3,4);
+ m = -2, 1, 5, -5,
+ 5, 5, 5, 5,
+ 9, 0, -4, -2;
+
+ s = -1, 1, 1, -1,
+ 1, 1, 1, 1,
+ 1, 1, -1, -1;
+
+ DLIB_TEST(sign(m) == s);
+ DLIB_TEST(sign(matrix_cast<double>(m)) == matrix_cast<double>(s));
+ }
+
+ }
+
+
+ void test_matrix_IO()
+ {
+ dlib::rand rnd;
+ print_spinner();
+
+ for (int i = 0; i < 400; ++i)
+ {
+ ostringstream sout;
+ sout.precision(20);
+
+ matrix<double> m1, m2, m3;
+
+ const long r = rnd.get_random_32bit_number()%7+1;
+ const long c = rnd.get_random_32bit_number()%7+1;
+ const long num = rnd.get_random_32bit_number()%2+1;
+
+ m1 = randm(r,c,rnd);
+ sout << m1;
+ if (num != 1)
+ sout << "\n" << m1;
+
+ if (rnd.get_random_double() < 0.3)
+ sout << " \n";
+ else if (rnd.get_random_double() < 0.3)
+ sout << " \n\n 3 3 3 3";
+ else if (rnd.get_random_double() < 0.3)
+ sout << " \n \n v 3 3 3 3 3";
+
+ istringstream sin(sout.str());
+ sin >> m2;
+ DLIB_TEST_MSG(equal(m1,m2), m1 << "\n***********\n" << m2);
+
+ if (num != 1)
+ {
+ sin >> m3;
+ DLIB_TEST_MSG(equal(m1,m3), m1 << "\n***********\n" << m3);
+ }
+ }
+
+
+ {
+ istringstream sin(" 1 2\n3");
+ matrix<double> m;
+ DLIB_TEST(sin.good());
+ sin >> m;
+ DLIB_TEST(!sin.good());
+ }
+ {
+ istringstream sin("");
+ matrix<double> m;
+ DLIB_TEST(sin.good());
+ sin >> m;
+ DLIB_TEST(!sin.good());
+ }
+ }
+
+
+ void test_axpy()
+ {
+ const int n = 4;
+ matrix<double> B = dlib::randm(n,n);
+
+ matrix<double> g = dlib::uniform_matrix<double>(n,1,0.0);
+
+ const double tau = 1;
+
+ matrix<double> p = g + tau*dlib::colm(B,0);
+ matrix<double> q = dlib::colm(B,0);
+ DLIB_TEST(max(abs(p-q)) < 1e-14);
+
+ p = tau*dlib::colm(B,0);
+ q = dlib::colm(B,0);
+ DLIB_TEST(max(abs(p-q)) < 1e-14);
+
+
+
+
+ g = dlib::uniform_matrix<double>(n,n,0.0);
+ p = g + tau*B;
+ DLIB_TEST(max(abs(p-B)) < 1e-14);
+
+ p = g + tau*subm(B,get_rect(B));
+ DLIB_TEST(max(abs(p-B)) < 1e-14);
+
+ g = dlib::uniform_matrix<double>(2,2,0.0);
+ p = g + tau*subm(B,1,1,2,2);
+ DLIB_TEST(max(abs(p-subm(B,1,1,2,2))) < 1e-14);
+
+ set_subm(p,0,0,2,2) = g + tau*subm(B,1,1,2,2);
+ DLIB_TEST(max(abs(p-subm(B,1,1,2,2))) < 1e-14);
+ }
+
+
+ class matrix_tester : public tester
+ {
+ public:
+ matrix_tester (
+ ) :
+ tester ("test_matrix3",
+ "Runs tests on the matrix component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_axpy();
+ test_matrix_IO();
+ matrix_test();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/matrix4.cpp b/ml/dlib/dlib/test/matrix4.cpp
new file mode 100644
index 000000000..d2b83b712
--- /dev/null
+++ b/ml/dlib/dlib/test/matrix4.cpp
@@ -0,0 +1,1119 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+
+#include "tester.h"
+#include <dlib/memory_manager_stateless.h>
+#include <dlib/array2d.h>
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.matrix4");
+
+ void matrix_test (
+ )
+ /*!
+ ensures
+ - runs tests on the matrix stuff compliance with the specs
+ !*/
+ {
+ print_spinner();
+
+ {
+ matrix<double,3,3> m = round(10*randm(3,3));
+ matrix<double,3,1> v = round(10*randm(3,1));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+ {
+ matrix<double,3,3> m = round(10*randm(3,3));
+ matrix<double,1,3> v = round(10*randm(1,3));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+ {
+ matrix<double> m = round(10*randm(3,3));
+ matrix<double,1,3> v = round(10*randm(1,3));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+ {
+ matrix<double> m = round(10*randm(3,3));
+ matrix<double,0,3> v = round(10*randm(1,3));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+
+ {
+ matrix<double> m = round(10*randm(3,3));
+ matrix<double,1,0> v = round(10*randm(1,3));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+ {
+ matrix<double> m = round(10*randm(3,3));
+ matrix<double,3,0> v = round(10*randm(3,1));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+
+ {
+ matrix<double> m = round(10*randm(3,3));
+ matrix<double,0,1> v = round(10*randm(3,1));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+ {
+ matrix<double,3,3> m = round(10*randm(3,3));
+ matrix<double,3,0> v = round(10*randm(3,1));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+
+ {
+ matrix<double,3,3> m = round(10*randm(3,3));
+ matrix<double,0,1> v = round(10*randm(3,1));
+
+ DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) ));
+ DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) ));
+
+ DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m ));
+ DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m ));
+ }
+
+ {
+ matrix<double,3,5> m = round(10*randm(3,5));
+ matrix<double,0,1> v1 = round(10*randm(5,1));
+ matrix<double,0,1> v2 = round(10*randm(3,1));
+
+ DLIB_TEST(equal( m*diagm(v1) , m*tmp(diagm(v1)) ));
+ DLIB_TEST(equal( scale_columns(m,v1) , m*tmp(diagm(v1)) ));
+
+ DLIB_TEST(equal( diagm(v2)*m , tmp(diagm(v2))*m ));
+ DLIB_TEST(equal( scale_rows(m,v2) , tmp(diagm(v2))*m ));
+ }
+
+ {
+ matrix<double,3,5> m = round(10*randm(3,5));
+ matrix<double,5,1> v1 = round(10*randm(5,1));
+ matrix<double,3,1> v2 = round(10*randm(3,1));
+
+ DLIB_TEST(equal( m*diagm(v1) , m*tmp(diagm(v1)) ));
+ DLIB_TEST(equal( scale_columns(m,v1) , m*tmp(diagm(v1)) ));
+
+ DLIB_TEST(equal( diagm(v2)*m , tmp(diagm(v2))*m ));
+ DLIB_TEST(equal( scale_rows(m,v2) , tmp(diagm(v2))*m ));
+ }
+
+ }
+
+ void test_stuff()
+ {
+ print_spinner();
+
+ {
+ matrix<double> m(3,3), lr(3,3), ud(3,3);
+
+ m = 1,2,3,
+ 4,5,6,
+ 7,8,9;
+
+
+ lr = 3,2,1,
+ 6,5,4,
+ 9,8,7;
+
+ ud = 7,8,9,
+ 4,5,6,
+ 1,2,3;
+
+ DLIB_TEST(lr == fliplr(m));
+ DLIB_TEST(ud == flipud(m));
+ }
+ {
+ matrix<double> m(3,2), lr(3,2), ud(3,2);
+
+ m = 1,2,
+ 3,4,
+ 5,6;
+
+ lr = 2,1,
+ 4,3,
+ 6,5;
+
+ ud = 5,6,
+ 3,4,
+ 1,2;
+
+ DLIB_TEST(lr == fliplr(m));
+ DLIB_TEST(ud == flipud(m));
+ }
+
+ {
+ matrix<int> a, b;
+
+ a = matrix_cast<int>(round(10*randm(3,3)));
+ b = a;
+
+ b *= b;
+ DLIB_TEST(b == a*a);
+ }
+
+ {
+ matrix<double> m(2,3), m2(2,3);
+
+ m = 1,2,3,
+ 4,5,6;
+
+
+ m2 = 3,4,5,
+ 6,7,8;
+
+ DLIB_TEST(m + 2 == m2);
+ DLIB_TEST(2 + m == m2);
+
+ m += 2;
+ DLIB_TEST(m == m2);
+ m -= 2;
+
+ m2 = 0,1,2,
+ 3,4,5;
+
+ DLIB_TEST(m - 1 == m2);
+
+ m -= 1;
+ DLIB_TEST(m == m2);
+ m += 1;
+
+
+ m2 = 5,4,3,
+ 2,1,0;
+
+ DLIB_TEST(6 - m == m2);
+ }
+
+ {
+ matrix<float> m(2,3), m2(2,3);
+
+ m = 1,2,3,
+ 4,5,6;
+
+
+ m2 = 3,4,5,
+ 6,7,8;
+
+ DLIB_TEST(m + 2 == m2);
+ DLIB_TEST(2 + m == m2);
+
+ m += 2;
+ DLIB_TEST(m == m2);
+ m -= 2;
+
+ m2 = 0,1,2,
+ 3,4,5;
+
+ DLIB_TEST(m - 1 == m2);
+
+ m -= 1;
+ DLIB_TEST(m == m2);
+ m += 1;
+
+
+ m2 = 5,4,3,
+ 2,1,0;
+
+ DLIB_TEST(6 - m == m2);
+ }
+
+ {
+ matrix<int> m(2,3), m2(2,3);
+
+ m = 1,2,3,
+ 4,5,6;
+
+
+ m2 = 3,4,5,
+ 6,7,8;
+
+ DLIB_TEST(m + 2 == m2);
+ DLIB_TEST(2 + m == m2);
+
+ m += 2;
+ DLIB_TEST(m == m2);
+ m -= 2;
+
+ m2 = 0,1,2,
+ 3,4,5;
+
+ DLIB_TEST(m - 1 == m2);
+
+ m -= 1;
+ DLIB_TEST(m == m2);
+ m += 1;
+
+
+ m2 = 5,4,3,
+ 2,1,0;
+
+ DLIB_TEST(6 - m == m2);
+ }
+
+ {
+ matrix<int,2,3> m, m2;
+
+ m = 1,2,3,
+ 4,5,6;
+
+
+ m2 = 3,4,5,
+ 6,7,8;
+
+ DLIB_TEST(m + 2 == m2);
+ DLIB_TEST(2 + m == m2);
+
+ m += 2;
+ DLIB_TEST(m == m2);
+ m -= 2;
+
+ m2 = 0,1,2,
+ 3,4,5;
+
+ DLIB_TEST(m - 1 == m2);
+
+ m -= 1;
+ DLIB_TEST(m == m2);
+ m += 1;
+
+
+ m2 = 5,4,3,
+ 2,1,0;
+
+ DLIB_TEST(6 - m == m2);
+ }
+
+ {
+ matrix<double> m(2,3), m2(3,2);
+
+ m = 1,2,3,
+ 4,5,6;
+
+ m2 = 2,5,
+ 3,6,
+ 4,7;
+
+ DLIB_TEST(trans(m+1) == m2);
+ DLIB_TEST(trans(m)+1 == m2);
+ DLIB_TEST(1+trans(m) == m2);
+ DLIB_TEST(1+m-1 == m);
+
+ m = trans(m+1);
+ DLIB_TEST(m == m2);
+ m = trans(m-1);
+ DLIB_TEST(trans(m+1) == m2);
+ m = trans(m)+1;
+ DLIB_TEST(m == m2);
+ }
+
+ {
+ matrix<double> d(3,1), di(3,1);
+ matrix<double> m(3,3);
+
+ m = 1,2,3,
+ 4,5,6,
+ 7,8,9;
+
+ d = 1,2,3;
+
+ di = 1, 1/2.0, 1/3.0;
+
+ DLIB_TEST(inv(diagm(d)) == diagm(di));
+ DLIB_TEST(pinv(diagm(d)) == diagm(di));
+ DLIB_TEST(inv(diagm(d))*m == tmp(diagm(di))*m);
+ DLIB_TEST(m*inv(diagm(d)) == m*tmp(diagm(di)));
+
+ DLIB_TEST(equal(inv(diagm(d)) + m , tmp(diagm(di)) + m));
+ DLIB_TEST(equal(m + inv(diagm(d)) , tmp(diagm(di)) + m));
+
+ DLIB_TEST((m + identity_matrix<double>(3) == m + tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + identity_matrix<double,3>() == m + tmp(identity_matrix<double,3>())));
+ DLIB_TEST((m + 2*identity_matrix<double>(3) == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + 2*identity_matrix<double,3>() == m + 2*tmp(identity_matrix<double,3>())));
+ DLIB_TEST((m + identity_matrix<double>(3)*2 == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + identity_matrix<double,3>()*2 == m + 2*tmp(identity_matrix<double,3>())));
+
+ DLIB_TEST((identity_matrix<double>(3) + m == m + tmp(identity_matrix<double>(3))));
+ DLIB_TEST((identity_matrix<double,3>() + m == m + tmp(identity_matrix<double,3>())));
+ DLIB_TEST((2*identity_matrix<double>(3) + m == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((2*identity_matrix<double,3>() + m == m + 2*tmp(identity_matrix<double,3>())));
+
+ }
+ {
+ matrix<double,3,1> d(3,1), di(3,1);
+ matrix<double,3,3> m(3,3);
+
+ m = 1,2,3,
+ 4,5,6,
+ 7,8,9;
+
+ d = 1,2,3;
+
+ di = 1, 1/2.0, 1/3.0;
+
+ DLIB_TEST(equal(inv(diagm(d)) , diagm(di)));
+ DLIB_TEST(equal(inv(diagm(d)) , diagm(di)));
+ DLIB_TEST(equal(inv(diagm(d))*m , tmp(diagm(di))*m));
+ DLIB_TEST(equal(m*inv(diagm(d)) , m*tmp(diagm(di))));
+
+ DLIB_TEST_MSG(equal(inv(diagm(d)) + m , tmp(diagm(di)) + m),
+ (inv(diagm(d)) + m) - (tmp(diagm(di)) + m) );
+ DLIB_TEST(equal(m + inv(diagm(d)) , tmp(diagm(di)) + m));
+
+
+ DLIB_TEST((m + identity_matrix<double>(3) == m + tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + identity_matrix<double,3>() == m + tmp(identity_matrix<double,3>())));
+ DLIB_TEST((m + 2*identity_matrix<double>(3) == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + 2*identity_matrix<double,3>() == m + 2*tmp(identity_matrix<double,3>())));
+ DLIB_TEST((m + identity_matrix<double>(3)*2 == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + identity_matrix<double,3>()*2 == m + 2*tmp(identity_matrix<double,3>())));
+
+ DLIB_TEST((identity_matrix<double>(3) + m == m + tmp(identity_matrix<double>(3))));
+ DLIB_TEST((identity_matrix<double,3>() + m == m + tmp(identity_matrix<double,3>())));
+ DLIB_TEST((2*identity_matrix<double>(3) + m == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((2*identity_matrix<double,3>() + m == m + 2*tmp(identity_matrix<double,3>())));
+ }
+
+ {
+ matrix<double,1,3> d(1,3), di(1,3);
+ matrix<double,3,3> m(3,3);
+
+ m = 1,2,3,
+ 4,5,6,
+ 7,8,9;
+
+ d = 1,2,3;
+
+ di = 1, 1/2.0, 1/3.0;
+
+ DLIB_TEST(equal(inv(diagm(d)) , diagm(di)));
+ DLIB_TEST(equal(inv(diagm(d)) , diagm(di)));
+ DLIB_TEST(equal(inv(diagm(d))*m , tmp(diagm(di))*m));
+ DLIB_TEST(equal(m*inv(diagm(d)) , m*tmp(diagm(di))));
+
+ DLIB_TEST(equal(inv(diagm(d)) + m , tmp(diagm(di)) + m));
+ DLIB_TEST(equal(m + inv(diagm(d)) , tmp(diagm(di)) + m));
+
+
+ DLIB_TEST((m + identity_matrix<double>(3) == m + tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + identity_matrix<double,3>() == m + tmp(identity_matrix<double,3>())));
+ DLIB_TEST((m + 2*identity_matrix<double>(3) == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + 2*identity_matrix<double,3>() == m + 2*tmp(identity_matrix<double,3>())));
+ DLIB_TEST((m + identity_matrix<double>(3)*2 == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + identity_matrix<double,3>()*2 == m + 2*tmp(identity_matrix<double,3>())));
+
+ DLIB_TEST((identity_matrix<double>(3) + m == m + tmp(identity_matrix<double>(3))));
+ DLIB_TEST((identity_matrix<double,3>() + m == m + tmp(identity_matrix<double,3>())));
+ DLIB_TEST((2*identity_matrix<double>(3) + m == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((2*identity_matrix<double,3>() + m == m + 2*tmp(identity_matrix<double,3>())));
+ }
+
+ {
+ matrix<double,1,0> d(1,3), di(1,3);
+ matrix<double,0,3> m(3,3);
+
+ m = 1,2,3,
+ 4,5,6,
+ 7,8,9;
+
+ d = 1,2,3;
+
+ di = 1, 1/2.0, 1/3.0;
+
+ DLIB_TEST(equal(inv(diagm(d)) , diagm(di)));
+ DLIB_TEST(equal(inv(diagm(d)) , diagm(di)));
+ DLIB_TEST(equal(inv(diagm(d))*m , tmp(diagm(di))*m));
+ DLIB_TEST(equal(m*inv(diagm(d)) , m*tmp(diagm(di))));
+
+ DLIB_TEST(equal(inv(diagm(d)) + m , tmp(diagm(di)) + m));
+ DLIB_TEST(equal(m + inv(diagm(d)) , tmp(diagm(di)) + m));
+
+
+ DLIB_TEST((m + identity_matrix<double>(3) == m + tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + identity_matrix<double,3>() == m + tmp(identity_matrix<double,3>())));
+ DLIB_TEST((m + 2*identity_matrix<double>(3) == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + 2*identity_matrix<double,3>() == m + 2*tmp(identity_matrix<double,3>())));
+ DLIB_TEST((m + identity_matrix<double>(3)*2 == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((m + identity_matrix<double,3>()*2 == m + 2*tmp(identity_matrix<double,3>())));
+
+ DLIB_TEST((identity_matrix<double>(3) + m == m + tmp(identity_matrix<double>(3))));
+ DLIB_TEST((identity_matrix<double,3>() + m == m + tmp(identity_matrix<double,3>())));
+ DLIB_TEST((2*identity_matrix<double>(3) + m == m + 2*tmp(identity_matrix<double>(3))));
+ DLIB_TEST((2*identity_matrix<double,3>() + m == m + 2*tmp(identity_matrix<double,3>())));
+ }
+
+
+ {
+ matrix<double,3,1> d1, d2;
+
+ d1 = 1,2,3;
+
+ d2 = 2,3,4;
+
+ matrix<double,3,3> ans;
+ ans = 2, 0, 0,
+ 0, 6, 0,
+ 0, 0, 12;
+
+ DLIB_TEST(ans == diagm(d1)*diagm(d2));
+ }
+
+
+ dlib::rand rnd;
+ for (int i = 0; i < 1; ++i)
+ {
+ matrix<double> d1 = randm(4,1,rnd);
+ matrix<double,5,1> d2 = randm(5,1,rnd);
+
+ matrix<double,4,5> m = randm(4,5,rnd);
+
+ DLIB_TEST_MSG(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*m*diagm(d2)),
+ pointwise_multiply(d1*trans(d2), m) - diagm(d1)*m*diagm(d2)
+ );
+ DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*(m*diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , (diagm(d1)*m)*diagm(d2)));
+
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*m*inv(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*(m*inv(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , (inv(diagm(d1))*m)*inv(diagm(d2))));
+
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*m*(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*(m*(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , (inv(diagm(d1))*m)*(diagm(d2))));
+
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*m*inv(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*(m*inv(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , ((diagm(d1))*m)*inv(diagm(d2))));
+ }
+ for (int i = 0; i < 1; ++i)
+ {
+ matrix<double,4,1> d1 = randm(4,1,rnd);
+ matrix<double,5,1> d2 = randm(5,1,rnd);
+
+ matrix<double,4,5> m = randm(4,5,rnd);
+
+ DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*m*diagm(d2)));
+ DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*(m*diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , (diagm(d1)*m)*diagm(d2)));
+
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*m*inv(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*(m*inv(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , (inv(diagm(d1))*m)*inv(diagm(d2))));
+
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*m*(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*(m*(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , (inv(diagm(d1))*m)*(diagm(d2))));
+
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*m*inv(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*(m*inv(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , ((diagm(d1))*m)*inv(diagm(d2))));
+ }
+ for (int i = 0; i < 1; ++i)
+ {
+ matrix<double,4,1> d1 = randm(4,1,rnd);
+ matrix<double,5,1> d2 = randm(5,1,rnd);
+
+ matrix<double,0,0> m = randm(4,5,rnd);
+
+ DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*m*diagm(d2)));
+ DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*(m*diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , (diagm(d1)*m)*diagm(d2)));
+
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*m*inv(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*(m*inv(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , (inv(diagm(d1))*m)*inv(diagm(d2))));
+
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*m*(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*(m*(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , (inv(diagm(d1))*m)*(diagm(d2))));
+
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*m*inv(diagm(d2))));
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*(m*inv(diagm(d2)))));
+ DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , ((diagm(d1))*m)*inv(diagm(d2))));
+ }
+
+
+
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ matrix<double> m = randm(3,4) + 1;
+
+ DLIB_TEST(equal(1.0/m , reciprocal(m)));
+ DLIB_TEST(equal(0.0/m , zeros_matrix<double>(3,4)));
+ }
+ }
+
+ {
+ matrix<int> m(2,3);
+ m = 1,2,3,
+ 4,5,6;
+ matrix<int> M(2,3);
+ M = m;
+
+ DLIB_TEST(upperbound(m,6) == M);
+ DLIB_TEST(upperbound(m,60) == M);
+ DLIB_TEST(lowerbound(m,-2) == M);
+ DLIB_TEST(lowerbound(m,0) == M);
+
+ M = 2,2,3,
+ 4,5,6;
+ DLIB_TEST(lowerbound(m,2) == M);
+
+ M = 0,0,0,
+ 0,0,0;
+ DLIB_TEST(upperbound(m,0) == M);
+
+ M = 1,2,3,
+ 3,3,3;
+ DLIB_TEST(upperbound(m,3) == M);
+ }
+
+ {
+ matrix<double,9,5> A = randm(9,5);
+ matrix<double> B = A;
+
+ orthogonalize(A);
+ orthogonalize(B);
+
+ DLIB_TEST(equal(A,B));
+ }
+ }
+
+
+
+ template <
+ long D1,
+ long D2,
+ long D3,
+ long D4
+ >
+ void test_conv()
+ {
+ dlog << LINFO << D1 << " " << D2 << " " << D3 << " " << D4;
+ matrix<int,D1,D1> a(1,1);
+ matrix<int,D2,D2> b(2,2);
+ matrix<int,D3,D3> c(3,3);
+ matrix<int,D4,D1> d(4,1);
+
+ a = 4;
+
+ b = 1,2,
+ 3,4;
+
+ c = 1,2,3,
+ 4,5,6,
+ 7,8,9;
+
+ d = 1,
+ 2,
+ 3,
+ 4;
+
+ matrix<int> temp(4,4), temp2;
+ temp = 1, 4, 7, 6,
+ 7, 23, 33, 24,
+ 19, 53, 63, 42,
+ 21, 52, 59, 36;
+
+ DLIB_TEST(conv(b,c) == temp);
+ DLIB_TEST(conv(c,b) == temp);
+ DLIB_TEST(xcorr(c,flip(b)) == temp);
+
+ temp.set_size(2,2);
+ temp = 23, 33,
+ 53, 63;
+ DLIB_TEST(conv_same(b,c) == temp);
+ DLIB_TEST(xcorr_same(b,flip(c)) == temp);
+
+ temp2.set_size(2,2);
+ temp2 = 63, 53,
+ 33, 23;
+ DLIB_TEST(flip(temp) == temp2);
+ DLIB_TEST(flip(temp) == fliplr(flipud(temp)));
+
+ DLIB_TEST(conv_valid(b,c).nr() == 0);
+ DLIB_TEST(conv_valid(b,c).nc() == 0);
+
+ DLIB_TEST(conv_valid(c,b) == temp);
+ DLIB_TEST(xcorr_valid(c,flip(b)) == temp);
+
+ temp.set_size(1,1);
+ temp = 16;
+
+ DLIB_TEST(conv(a,a) == temp);
+ DLIB_TEST(conv_same(a,a) == temp);
+ DLIB_TEST(conv_valid(a,a) == temp);
+ DLIB_TEST(xcorr(a,a) == temp);
+ DLIB_TEST(xcorr_same(a,a) == temp);
+ DLIB_TEST(xcorr_valid(a,a) == temp);
+
+ temp.set_size(0,0);
+ DLIB_TEST(conv(temp,temp).nr() == 0);
+ DLIB_TEST(conv(temp,temp).nc() == 0);
+ DLIB_TEST(conv_same(temp,temp).nr() == 0);
+ DLIB_TEST(conv_same(temp,temp).nc() == 0);
+ DLIB_TEST_MSG(conv_valid(temp,temp).nr() == 0, conv_valid(temp,temp).nr());
+ DLIB_TEST(conv_valid(temp,temp).nc() == 0);
+ DLIB_TEST(conv(c,temp).nr() == 0);
+ DLIB_TEST(conv(c,temp).nc() == 0);
+ DLIB_TEST(conv_same(c,temp).nr() == 0);
+ DLIB_TEST(conv_same(c,temp).nc() == 0);
+ DLIB_TEST(conv_valid(c,temp).nr() == 0);
+ DLIB_TEST(conv_valid(c,temp).nc() == 0);
+ DLIB_TEST(conv(temp,c).nr() == 0);
+ DLIB_TEST(conv(temp,c).nc() == 0);
+ DLIB_TEST(conv_same(temp,c).nr() == 0);
+ DLIB_TEST(conv_same(temp,c).nc() == 0);
+ DLIB_TEST(conv_valid(temp,c).nr() == 0);
+ DLIB_TEST(conv_valid(temp,c).nc() == 0);
+
+ temp.set_size(5,2);
+ temp = 1, 2,
+ 5, 8,
+ 9, 14,
+ 13, 20,
+ 12, 16;
+ DLIB_TEST(conv(b,d) == temp);
+ DLIB_TEST(xcorr(b,flip(d)) == temp);
+
+ temp.set_size(2,2);
+ temp = 9, 14,
+ 13, 20;
+ DLIB_TEST(conv_same(b,d) == temp);
+ DLIB_TEST(xcorr_same(b,flip(d)) == temp);
+
+ DLIB_TEST(conv_valid(b,d).nr() == 0);
+ DLIB_TEST(xcorr_valid(b,flip(d)).nr() == 0);
+ DLIB_TEST_MSG(conv_valid(b,d).nc() == 0, conv_valid(b,d).nc());
+ DLIB_TEST(xcorr_valid(b,flip(d)).nc() == 0);
+
+ temp.set_size(5,5);
+ temp = 1, 4, 10, 12, 9,
+ 8, 26, 56, 54, 36,
+ 30, 84, 165, 144, 90,
+ 56, 134, 236, 186, 108,
+ 49, 112, 190, 144, 81;
+
+ DLIB_TEST(conv(c,c) == temp);
+ DLIB_TEST(xcorr(c,flip(c)) == temp);
+ matrix<int> temp3 = c;
+ temp3 = conv(temp3,c);
+ DLIB_TEST(temp3 == temp);
+
+ temp3 = c;
+ temp3 = conv(c,temp3);
+ DLIB_TEST(temp3 == temp);
+
+
+ temp.set_size(3,3);
+ temp = 26, 56, 54,
+ 84, 165, 144,
+ 134, 236, 186;
+ DLIB_TEST(conv_same(c,c) == temp);
+ DLIB_TEST(xcorr_same(c,flip(c)) == temp);
+ temp3 = c;
+ temp3 = conv_same(c,temp3);
+ DLIB_TEST(temp3 == temp);
+ temp3 = c;
+ temp3 = conv_same(temp3,c);
+ DLIB_TEST(temp3 == temp);
+
+ temp.set_size(1,1);
+ temp = 165;
+ DLIB_TEST(conv_valid(c,c) == temp);
+ DLIB_TEST(xcorr_valid(c,flip(c)) == temp);
+ temp3 = c;
+ temp3 = conv_valid(c,temp3);
+ DLIB_TEST(temp3 == temp);
+ temp3 = c;
+ temp3 = conv_valid(temp3,c);
+ DLIB_TEST(temp3 == temp);
+
+
+ dlib::rand rnd;
+ for (int i = 0; i < 3; ++i)
+ {
+ matrix<complex<int> > a, b;
+ a = complex_matrix(matrix_cast<int>(round(20*randm(2,7,rnd))),
+ matrix_cast<int>(round(20*randm(2,7,rnd))));
+ b = complex_matrix(matrix_cast<int>(round(20*randm(3,2,rnd))),
+ matrix_cast<int>(round(20*randm(3,2,rnd))));
+
+ DLIB_TEST(xcorr(a,b) == conv(a, flip(conj(b))));
+ DLIB_TEST(xcorr_valid(a,b) == conv_valid(a, flip(conj(b))));
+ DLIB_TEST(xcorr_same(a,b) == conv_same(a, flip(conj(b))));
+ }
+
+
+ for (int i = 0; i < 30; ++i)
+ {
+ auto nr1 = rnd.get_integer_in_range(1,30);
+ auto nc1 = rnd.get_integer_in_range(1,30);
+ auto nr2 = rnd.get_integer_in_range(1,30);
+ auto nc2 = rnd.get_integer_in_range(1,30);
+ matrix<double> a, b;
+ a = randm(nr1,nc1,rnd);
+ b = randm(nr2,nc2,rnd);
+
+ DLIB_TEST(max(abs(xcorr(a,b) - xcorr_fft(a,b))) < 1e-12);
+ }
+ }
+
+ void test_complex()
+ {
+ matrix<complex<double> > a, b;
+
+ a = complex_matrix(linspace(1,7,7), linspace(2,8,7));
+ b = complex_matrix(linspace(4,10,7), linspace(2,8,7));
+
+ DLIB_TEST(mean(a) == complex<double>(4, 5));
+ }
+
+ void test_setsubs()
+ {
+ {
+ matrix<double> m(3,3);
+ m = 0;
+
+ set_colm(m,0) += 1;
+ set_rowm(m,0) += 1;
+ set_subm(m,1,1,2,2) += 5;
+
+ matrix<double> m2(3,3);
+ m2 = 2, 1, 1,
+ 1, 5, 5,
+ 1, 5, 5;
+
+ DLIB_TEST(m == m2);
+
+ set_colm(m,0) -= 1;
+ set_rowm(m,0) -= 1;
+ set_subm(m,1,1,2,2) -= 5;
+
+ m2 = 0;
+ DLIB_TEST(m == m2);
+
+ matrix<double,1,3> r;
+ matrix<double,3,1> c;
+ matrix<double,2,2> b;
+ r = 1,2,3;
+
+ c = 2,
+ 3,
+ 4;
+
+ b = 2,3,
+ 4,5;
+
+ set_colm(m,1) += c;
+ set_rowm(m,1) += r;
+ set_subm(m,1,1,2,2) += b;
+
+ m2 = 0, 2, 0,
+ 1, 7, 6,
+ 0, 8, 5;
+
+ DLIB_TEST(m2 == m);
+
+ set_colm(m,1) -= c;
+ set_rowm(m,1) -= r;
+ set_subm(m,1,1,2,2) -= b;
+
+ m2 = 0;
+ DLIB_TEST(m2 == m);
+
+
+ // check that the code path for destructive aliasing works right.
+ m = 2*identity_matrix<double>(3);
+ set_colm(m,1) += m*c;
+ m2 = 2, 4, 0,
+ 0, 8, 0,
+ 0, 8, 2;
+ DLIB_TEST(m == m2);
+
+ m = 2*identity_matrix<double>(3);
+ set_colm(m,1) -= m*c;
+ m2 = 2, -4, 0,
+ 0, -4, 0,
+ 0, -8, 2;
+ DLIB_TEST(m == m2);
+
+ m = 2*identity_matrix<double>(3);
+ set_rowm(m,1) += r*m;
+ m2 = 2, 0, 0,
+ 2, 6, 6,
+ 0, 0, 2;
+ DLIB_TEST(m == m2);
+
+ m = 2*identity_matrix<double>(3);
+ set_rowm(m,1) -= r*m;
+ m2 = 2, 0, 0,
+ -2, -2, -6,
+ 0, 0, 2;
+ DLIB_TEST(m == m2);
+
+ m = identity_matrix<double>(3);
+ const rectangle rect(0,0,1,1);
+ set_subm(m,rect) += subm(m,rect)*b;
+ m2 = 3, 3, 0,
+ 4, 6, 0,
+ 0, 0, 1;
+ DLIB_TEST(m == m2);
+
+ m = identity_matrix<double>(3);
+ set_subm(m,rect) -= subm(m,rect)*b;
+ m2 = -1, -3, 0,
+ -4, -4, 0,
+ 0, 0, 1;
+ DLIB_TEST(m == m2);
+
+ }
+
+ {
+ matrix<double,1,1> a, b;
+ a = 2;
+ b = 3;
+ DLIB_TEST(dot(a,b) == 6);
+ }
+ {
+ matrix<double,1,1> a;
+ matrix<double,0,1> b(1);
+ a = 2;
+ b = 3;
+ DLIB_TEST(dot(a,b) == 6);
+ DLIB_TEST(dot(b,a) == 6);
+ }
+ {
+ matrix<double,1,1> a;
+ matrix<double,1,0> b(1);
+ a = 2;
+ b = 3;
+ DLIB_TEST(dot(a,b) == 6);
+ DLIB_TEST(dot(b,a) == 6);
+ }
+ }
+
+ template <typename T>
+ std::vector<int> tovect1(const T& m)
+ {
+ std::vector<int> temp;
+ for (typename T::const_iterator i = m.begin(); i != m.end(); ++i)
+ {
+ temp.push_back(*i);
+ }
+ return temp;
+ }
+
+ template <typename T>
+ std::vector<int> tovect2(const T& m)
+ {
+ std::vector<int> temp;
+ for (typename T::const_iterator i = m.begin(); i != m.end(); i++)
+ {
+ temp.push_back(*i);
+ }
+ return temp;
+ }
+
+ template <typename T>
+ std::vector<int> tovect3(const T& m_)
+ {
+ matrix<int> m(m_);
+ std::vector<int> temp;
+ for (matrix<int>::iterator i = m.begin(); i != m.end(); ++i)
+ {
+ temp.push_back(*i);
+ }
+ return temp;
+ }
+
+ template <typename T>
+ std::vector<int> tovect4(const T& m_)
+ {
+ matrix<int> m(m_);
+ std::vector<int> temp;
+ for (matrix<int>::iterator i = m.begin(); i != m.end(); i++)
+ {
+ temp.push_back(*i);
+ }
+ return temp;
+ }
+
+ void test_iterators()
+ {
+ matrix<int> m(3,2);
+ m = 1,2,3,
+ 4,5,6;
+
+ std::vector<int> v1 = tovect1(m);
+ std::vector<int> v2 = tovect2(m);
+ std::vector<int> v3 = tovect3(m);
+ std::vector<int> v4 = tovect4(m);
+
+ std::vector<int> v5 = tovect1(m+m);
+ std::vector<int> v6 = tovect2(m+m);
+ std::vector<int> v7 = tovect3(m+m);
+ std::vector<int> v8 = tovect4(m+m);
+
+
+ std::vector<int> a1, a2;
+ for (int i = 1; i <= 6; ++i)
+ {
+ a1.push_back(i);
+ a2.push_back(i*2);
+ }
+
+ DLIB_TEST(max(abs(mat(v1) - mat(a1))) == 0);
+ DLIB_TEST(max(abs(mat(v2) - mat(a1))) == 0);
+ DLIB_TEST(max(abs(mat(v3) - mat(a1))) == 0);
+ DLIB_TEST(max(abs(mat(v4) - mat(a1))) == 0);
+
+ DLIB_TEST(max(abs(mat(v5) - mat(a2))) == 0);
+ DLIB_TEST(max(abs(mat(v6) - mat(a2))) == 0);
+ DLIB_TEST(max(abs(mat(v7) - mat(a2))) == 0);
+ DLIB_TEST(max(abs(mat(v8) - mat(a2))) == 0);
+ }
+
+ void test_linpiece()
+ {
+ matrix<double,0,1> temp = linpiece(5, linspace(-1, 9, 2));
+ DLIB_CASSERT(temp.size() == 1,"");
+ DLIB_CASSERT(std::abs(temp(0) - 6) < 1e-13,"");
+
+ temp = linpiece(5, linspace(-1, 9, 6));
+ DLIB_CASSERT(temp.size() == 5,"");
+ DLIB_CASSERT(std::abs(temp(0) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(1) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(2) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(3) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(4) - 0) < 1e-13,"");
+
+ temp = linpiece(4, linspace(-1, 9, 6));
+ DLIB_CASSERT(temp.size() == 5,"");
+ DLIB_CASSERT(std::abs(temp(0) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(1) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(2) - 1) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(3) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(4) - 0) < 1e-13,"");
+
+ temp = linpiece(40, linspace(-1, 9, 6));
+ DLIB_CASSERT(temp.size() == 5,"");
+ DLIB_CASSERT(std::abs(temp(0) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(1) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(2) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(3) - 2) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(4) - 2) < 1e-13,"");
+
+ temp = linpiece(-40, linspace(-1, 9, 6));
+ DLIB_CASSERT(temp.size() == 5,"");
+ DLIB_CASSERT(std::abs(temp(0) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(1) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(2) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(3) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(4) - 0) < 1e-13,"");
+
+ temp = linpiece(0, linspace(-1, 9, 6));
+ DLIB_CASSERT(temp.size() == 5,"");
+ DLIB_CASSERT(std::abs(temp(0) - 1) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(1) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(2) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(3) - 0) < 1e-13,"");
+ DLIB_CASSERT(std::abs(temp(4) - 0) < 1e-13,"");
+
+ }
+
+ class matrix_tester : public tester
+ {
+ public:
+ matrix_tester (
+ ) :
+ tester ("test_matrix4",
+ "Runs tests on the scale_rows and scale_columns functions.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_iterators();
+ test_setsubs();
+
+ test_conv<0,0,0,0>();
+ test_conv<1,2,3,4>();
+
+ test_stuff();
+ for (int i = 0; i < 10; ++i)
+ matrix_test();
+
+ test_complex();
+ test_linpiece();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/matrix_chol.cpp b/ml/dlib/dlib/test/matrix_chol.cpp
new file mode 100644
index 000000000..b46c4866d
--- /dev/null
+++ b/ml/dlib/dlib/test/matrix_chol.cpp
@@ -0,0 +1,182 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+#include <dlib/string.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.matrix_chol");
+
+ dlib::rand rnd;
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename mat_type>
+ const matrix<typename mat_type::type> symm(const mat_type& m) { return m*trans(m); }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename type>
+ const matrix<type> randmat(long r, long c)
+ {
+ matrix<type> m(r,c);
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = 0; col < m.nc(); ++col)
+ {
+ m(row,col) = static_cast<type>(rnd.get_random_double());
+ }
+ }
+
+ return m;
+ }
+
+ template <typename type, long NR, long NC>
+ const matrix<type,NR,NC> randmat()
+ {
+ matrix<type,NR,NC> m;
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = 0; col < m.nc(); ++col)
+ {
+ m(row,col) = static_cast<type>(rnd.get_random_double());
+ }
+ }
+
+ return m;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename matrix_type>
+ void test_cholesky ( const matrix_type& m)
+ {
+ typedef typename matrix_type::type type;
+ const type eps = 10*max(abs(m))*sqrt(std::numeric_limits<type>::epsilon());
+ dlog << LDEBUG << "test_cholesky(): " << m.nr() << " x " << m.nc() << " eps: " << eps;
+ print_spinner();
+
+
+ cholesky_decomposition<matrix_type> test(m);
+
+ // none of the matrices we should be passing in to test_cholesky() should be non-spd.
+ DLIB_TEST(test.is_spd() == true);
+
+ type temp;
+ DLIB_TEST_MSG( (temp= max(abs(test.get_l()*trans(test.get_l()) - m))) < eps,temp);
+
+ {
+ matrix<type> mat = chol(m);
+ DLIB_TEST_MSG( (temp= max(abs(mat*trans(mat) - m))) < eps,temp);
+ }
+
+
+ matrix<type> m2;
+ matrix<type,0,1> col;
+
+ m2 = identity_matrix<type>(m.nr());
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ m2 = randmat<type>(m.nr(),5);
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ m2 = randmat<type>(m.nr(),1);
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ col = randmat<type>(m.nr(),1);
+ DLIB_TEST_MSG(equal(m*test.solve(col), col,eps),max(abs(m*test.solve(m2)- m2)));
+
+ // now make us a non-spd matrix
+ if (m.nr() > 2)
+ {
+ matrix<type> sm(lowerm(m));
+ sm(1,1) = 0;
+
+ cholesky_decomposition<matrix_type> test2(sm);
+ DLIB_TEST_MSG(test2.is_spd() == false, test2.get_l());
+
+
+ cholesky_decomposition<matrix_type> test3(sm*trans(sm));
+ DLIB_TEST_MSG(test3.is_spd() == false, test3.get_l());
+
+ sm = sm*trans(sm);
+ sm(1,1) = 5;
+ sm(1,0) -= 1;
+ cholesky_decomposition<matrix_type> test4(sm);
+ DLIB_TEST_MSG(test4.is_spd() == false, test4.get_l());
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void matrix_test_double()
+ {
+
+ test_cholesky(uniform_matrix<double>(1,1,1) + 10*symm(randmat<double>(1,1)));
+ test_cholesky(uniform_matrix<double>(2,2,1) + 10*symm(randmat<double>(2,2)));
+ test_cholesky(uniform_matrix<double>(3,3,1) + 10*symm(randmat<double>(3,3)));
+ test_cholesky(uniform_matrix<double>(4,4,1) + 10*symm(randmat<double>(4,4)));
+ test_cholesky(uniform_matrix<double>(15,15,1) + 10*symm(randmat<double>(15,15)));
+ test_cholesky(uniform_matrix<double>(101,101,1) + 10*symm(randmat<double>(101,101)));
+
+ typedef matrix<double,0,0,default_memory_manager, column_major_layout> mat;
+ test_cholesky(mat(uniform_matrix<double>(101,101,1) + 10*symm(randmat<double>(101,101))));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void matrix_test_float()
+ {
+
+ test_cholesky(uniform_matrix<float>(1,1,1) + 2*symm(randmat<float>(1,1)));
+ test_cholesky(uniform_matrix<float>(2,2,1) + 2*symm(randmat<float>(2,2)));
+ test_cholesky(uniform_matrix<float>(3,3,1) + 2*symm(randmat<float>(3,3)));
+
+ typedef matrix<float,0,0,default_memory_manager, column_major_layout> mat;
+ test_cholesky(mat(uniform_matrix<float>(3,3,1) + 2*symm(randmat<float>(3,3))));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class matrix_tester : public tester
+ {
+ public:
+ matrix_tester (
+ ) :
+ tester ("test_matrix_chol",
+ "Runs tests on the matrix cholesky component.")
+ {
+ rnd.set_seed(cast_to_string(time(0)));
+ }
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "seed string: " << rnd.get_seed();
+
+ dlog << LINFO << "begin testing with double";
+ matrix_test_double();
+ dlog << LINFO << "begin testing with float";
+ matrix_test_float();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/matrix_eig.cpp b/ml/dlib/dlib/test/matrix_eig.cpp
new file mode 100644
index 000000000..9fbce6598
--- /dev/null
+++ b/ml/dlib/dlib/test/matrix_eig.cpp
@@ -0,0 +1,245 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+#include <dlib/string.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.matrix_eig");
+
+ dlib::rand rnd;
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename type>
+ const matrix<type> randm(long r, long c)
+ {
+ matrix<type> m(r,c);
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = 0; col < m.nc(); ++col)
+ {
+ m(row,col) = static_cast<type>(rnd.get_random_double());
+ }
+ }
+
+ return m;
+ }
+
+ template <typename type, long NR, long NC>
+ const matrix<type,NR,NC> randm()
+ {
+ matrix<type,NR,NC> m;
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = 0; col < m.nc(); ++col)
+ {
+ m(row,col) = static_cast<type>(rnd.get_random_double());
+ }
+ }
+
+ return m;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename matrix_type, typename U>
+ void test_eigenvalue_impl ( const matrix_type& m, const eigenvalue_decomposition<U>& test )
+ {
+ typedef typename matrix_type::type type;
+ const type eps = 10*max(abs(m))*sqrt(std::numeric_limits<type>::epsilon());
+ dlog << LDEBUG << "test_eigenvalue(): " << m.nr() << " x " << m.nc() << " eps: " << eps;
+ print_spinner();
+
+
+ DLIB_TEST(test.dim() == m.nr());
+
+ // make sure all the various ways of asking for the eigenvalues are actually returning a
+ // consistent set of eigenvalues.
+ DLIB_TEST(equal(real(test.get_eigenvalues()), test.get_real_eigenvalues(), eps));
+ DLIB_TEST(equal(imag(test.get_eigenvalues()), test.get_imag_eigenvalues(), eps));
+ DLIB_TEST(equal(real(diag(test.get_d())), test.get_real_eigenvalues(), eps));
+ DLIB_TEST(equal(imag(diag(test.get_d())), test.get_imag_eigenvalues(), eps));
+
+ matrix<type> eig1 ( real_eigenvalues(m));
+ matrix<type> eig2 ( test.get_real_eigenvalues());
+ sort(&eig1(0), &eig1(0) + eig1.size());
+ sort(&eig2(0), &eig2(0) + eig2.size());
+ DLIB_TEST(max(abs(eig1 - eig2)) < eps);
+
+ const matrix<type> V = test.get_pseudo_v();
+ const matrix<type> D = test.get_pseudo_d();
+ const matrix<complex<type> > CV = test.get_v();
+ const matrix<complex<type> > CD = test.get_d();
+ const matrix<complex<type> > CM = complex_matrix(m, uniform_matrix<type>(m.nr(),m.nc(),0));
+
+ DLIB_TEST(V.nr() == test.dim());
+ DLIB_TEST(V.nc() == test.dim());
+ DLIB_TEST(D.nr() == test.dim());
+ DLIB_TEST(D.nc() == test.dim());
+
+ // CD is a diagonal matrix
+ DLIB_TEST(diagm(diag(CD)) == CD);
+
+ // verify that these things are actually eigenvalues and eigenvectors of m
+ DLIB_TEST_MSG(max(abs(m*V - V*D)) < eps, max(abs(m*V - V*D)) << " " << eps);
+ DLIB_TEST(max(norm(CM*CV - CV*CD)) < eps);
+
+ // if m is a symmetric matrix
+ if (max(abs(m-trans(m))) < 1e-5)
+ {
+ dlog << LTRACE << "m is symmetric";
+ // there aren't any imaginary eigenvalues
+ DLIB_TEST(max(abs(test.get_imag_eigenvalues())) < eps);
+ DLIB_TEST(diagm(diag(D)) == D);
+
+ // only check the determinant against the eigenvalues for small matrices
+ // because for huge ones the determinant might be so big it overflows a floating point number.
+ if (m.nr() < 50)
+ {
+ const type mdet = det(m);
+ DLIB_TEST_MSG(std::abs(prod(test.get_real_eigenvalues()) - mdet) < std::abs(mdet)*sqrt(std::numeric_limits<type>::epsilon()),
+ std::abs(prod(test.get_real_eigenvalues()) - mdet) <<" eps: " << std::abs(mdet)*sqrt(std::numeric_limits<type>::epsilon())
+ << " mdet: "<< mdet << " prod(eig): " << prod(test.get_real_eigenvalues())
+ );
+ }
+
+ // V is orthogonal
+ DLIB_TEST(equal(V*trans(V), identity_matrix<type>(test.dim()), eps));
+ DLIB_TEST(equal(m , V*D*trans(V), eps));
+ }
+ else
+ {
+ dlog << LTRACE << "m is NOT symmetric";
+ DLIB_TEST_MSG(equal(m , V*D*inv(V), eps), max(abs(m - V*D*inv(V))));
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename matrix_type>
+ void test_eigenvalue ( const matrix_type& m )
+ {
+ typedef typename matrix_type::type type;
+ typedef typename matrix_type::mem_manager_type MM;
+ matrix<type,matrix_type::NR, matrix_type::NC, MM, row_major_layout> mr(m);
+ matrix<type,matrix_type::NR, matrix_type::NC, MM, column_major_layout> mc(m);
+
+ {
+ eigenvalue_decomposition<matrix_type> test(mr);
+ test_eigenvalue_impl(mr, test);
+
+ eigenvalue_decomposition<matrix_type> test_symm(make_symmetric(mr));
+ test_eigenvalue_impl(make_symmetric(mr), test_symm);
+ }
+
+ {
+ eigenvalue_decomposition<matrix_type> test(mc);
+ test_eigenvalue_impl(mc, test);
+
+ eigenvalue_decomposition<matrix_type> test_symm(make_symmetric(mc));
+ test_eigenvalue_impl(make_symmetric(mc), test_symm);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void matrix_test_double()
+ {
+
+ test_eigenvalue(10*randm<double>(1,1));
+ test_eigenvalue(10*randm<double>(2,2));
+ test_eigenvalue(10*randm<double>(3,3));
+ test_eigenvalue(10*randm<double>(4,4));
+ test_eigenvalue(10*randm<double>(15,15));
+ test_eigenvalue(10*randm<double>(150,150));
+
+ test_eigenvalue(10*randm<double,1,1>());
+ test_eigenvalue(10*randm<double,2,2>());
+ test_eigenvalue(10*randm<double,3,3>());
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void matrix_test_float()
+ {
+
+ test_eigenvalue(10*randm<float>(1,1));
+ test_eigenvalue(10*randm<float>(2,2));
+ test_eigenvalue(10*randm<float>(3,3));
+ test_eigenvalue(10*randm<float>(4,4));
+ test_eigenvalue(10*randm<float>(15,15));
+ test_eigenvalue(10*randm<float>(50,50));
+
+ test_eigenvalue(10*randm<float,1,1>());
+ test_eigenvalue(10*randm<float,2,2>());
+ test_eigenvalue(10*randm<float,3,3>());
+ }
+
+ template <int dims>
+ void test_eigenvalue2()
+ {
+ for (int seed = 0; seed < 10; ++seed)
+ {
+ print_spinner();
+ matrix<double> H = gaussian_randm(dims,dims,seed);
+ H = H*trans(H);
+
+ eigenvalue_decomposition<matrix<double> > eig(H);
+ matrix<double> HH = eig.get_pseudo_v()*diagm(eig.get_real_eigenvalues())*trans(eig.get_pseudo_v());
+ DLIB_TEST_MSG(max(abs(H - HH))<1e-12, "dims: " << dims << " error: " << max(abs(H - HH)));
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class matrix_tester : public tester
+ {
+ public:
+ matrix_tester (
+ ) :
+ tester ("test_matrix_eig",
+ "Runs tests on the matrix eigen decomp component.")
+ {
+ //rnd.set_seed(cast_to_string(time(0)));
+ }
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "seed string: " << rnd.get_seed();
+
+ dlog << LINFO << "begin testing with double";
+ matrix_test_double();
+ dlog << LINFO << "begin testing with float";
+ matrix_test_float();
+
+ test_eigenvalue2<10>();
+ test_eigenvalue2<11>();
+ test_eigenvalue2<3>();
+ test_eigenvalue2<2>();
+ test_eigenvalue2<1>();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/matrix_lu.cpp b/ml/dlib/dlib/test/matrix_lu.cpp
new file mode 100644
index 000000000..f5425b355
--- /dev/null
+++ b/ml/dlib/dlib/test/matrix_lu.cpp
@@ -0,0 +1,223 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+#include <dlib/string.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.matrix_lu");
+
+ dlib::rand rnd;
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename mat_type>
+ const matrix<typename mat_type::type> symm(const mat_type& m) { return m*trans(m); }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename type>
+ const matrix<type> randmat(long r, long c)
+ {
+ matrix<type> m(r,c);
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = 0; col < m.nc(); ++col)
+ {
+ m(row,col) = static_cast<type>(rnd.get_random_double());
+ }
+ }
+
+ return m;
+ }
+
+ template <typename type, long NR, long NC>
+ const matrix<type,NR,NC> randmat()
+ {
+ matrix<type,NR,NC> m;
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = 0; col < m.nc(); ++col)
+ {
+ m(row,col) = static_cast<type>(rnd.get_random_double());
+ }
+ }
+
+ return m;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename matrix_type>
+ void test_lu ( const matrix_type& m)
+ {
+ typedef typename matrix_type::type type;
+ const type eps = 10*max(abs(m))*sqrt(std::numeric_limits<type>::epsilon());
+ dlog << LDEBUG << "test_lu(): " << m.nr() << " x " << m.nc() << " eps: " << eps;
+ print_spinner();
+
+
+ lu_decomposition<matrix_type> test(m);
+
+ DLIB_TEST(test.is_square() == (m.nr() == m.nc()));
+
+ DLIB_TEST(test.nr() == m.nr());
+ DLIB_TEST(test.nc() == m.nc());
+
+ dlog << LDEBUG << "m.nr(): " << m.nr() << " m.nc(): " << m.nc();
+
+ type temp;
+ DLIB_TEST_MSG( (temp= max(abs(test.get_l()*test.get_u() - rowm(m,test.get_pivot())))) < eps,temp);
+
+ if (test.is_square())
+ {
+ // none of the matrices we should be passing in to test_lu() should be singular.
+ DLIB_TEST_MSG (abs(test.det()) > eps/100, "det: " << test.det() );
+ dlog << LDEBUG << "big det: " << test.det();
+
+ DLIB_TEST(test.is_singular() == false);
+
+ matrix<type> m2;
+ matrix<type,0,1> col;
+
+ m2 = identity_matrix<type>(m.nr());
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ m2 = randmat<type>(m.nr(),5);
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ m2 = randmat<type>(m.nr(),1);
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ col = randmat<type>(m.nr(),1);
+ DLIB_TEST_MSG(equal(m*test.solve(col), col,eps),max(abs(m*test.solve(m2)- m2)));
+
+ // now make us a singular matrix
+ if (m.nr() > 1)
+ {
+ matrix<type> sm(m);
+ set_colm(sm,0) = colm(sm,1);
+
+ lu_decomposition<matrix_type> test2(sm);
+ DLIB_TEST_MSG( (temp= max(abs(test2.get_l()*test2.get_u() - rowm(sm,test2.get_pivot())))) < eps,temp);
+
+ // these checks are only accurate for small matrices
+ if (test2.nr() < 100)
+ {
+ DLIB_TEST_MSG(test2.is_singular() == true,"det: " << test2.det());
+ DLIB_TEST_MSG(abs(test2.det()) < eps,"det: " << test2.det());
+ }
+
+ }
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void matrix_test_double()
+ {
+
+
+ test_lu(10*randmat<double>(2,2));
+ test_lu(10*randmat<double>(1,1));
+ test_lu(10*symm(randmat<double>(2,2)));
+ test_lu(10*randmat<double>(4,4));
+ test_lu(10*randmat<double>(9,4));
+ test_lu(10*randmat<double>(3,8));
+ test_lu(10*randmat<double>(15,15));
+ test_lu(2*symm(randmat<double>(15,15)));
+ test_lu(10*randmat<double>(100,100));
+ test_lu(10*randmat<double>(137,200));
+ test_lu(10*randmat<double>(200,101));
+
+ test_lu(10*randmat<double,2,2>());
+ test_lu(10*randmat<double,1,1>());
+ test_lu(10*randmat<double,4,3>());
+ test_lu(10*randmat<double,4,4>());
+ test_lu(10*randmat<double,9,4>());
+ test_lu(10*randmat<double,3,8>());
+ test_lu(10*randmat<double,15,15>());
+ test_lu(10*randmat<double,100,100>());
+ test_lu(10*randmat<double,137,200>());
+ test_lu(10*randmat<double,200,101>());
+
+ typedef matrix<double,0,0,default_memory_manager, column_major_layout> mat;
+ test_lu(mat(3*randmat<double>(4,4)));
+ test_lu(mat(3*randmat<double>(9,4)));
+ test_lu(mat(3*randmat<double>(3,8)));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void matrix_test_float()
+ {
+
+ // -------------------------------
+
+ test_lu(3*randmat<float>(1,1));
+ test_lu(3*randmat<float>(2,2));
+ test_lu(3*randmat<float>(4,4));
+ test_lu(3*randmat<float>(9,4));
+ test_lu(3*randmat<float>(3,8));
+ test_lu(3*randmat<float>(137,200));
+ test_lu(3*randmat<float>(200,101));
+
+ test_lu(3*randmat<float,1,1>());
+ test_lu(3*randmat<float,2,2>());
+ test_lu(3*randmat<float,4,3>());
+ test_lu(3*randmat<float,4,4>());
+ test_lu(3*randmat<float,9,4>());
+ test_lu(3*randmat<float,3,8>());
+ test_lu(3*randmat<float,137,200>());
+ test_lu(3*randmat<float,200,101>());
+
+ typedef matrix<float,0,0,default_memory_manager, column_major_layout> mat;
+ test_lu(mat(3*randmat<float>(4,4)));
+ test_lu(mat(3*randmat<float>(9,4)));
+ test_lu(mat(3*randmat<float>(3,8)));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class matrix_tester : public tester
+ {
+ public:
+ matrix_tester (
+ ) :
+ tester ("test_matrix_lu",
+ "Runs tests on the matrix LU component.")
+ {
+ //rnd.set_seed(cast_to_string(time(0)));
+ }
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "seed string: " << rnd.get_seed();
+
+ dlog << LINFO << "begin testing with double";
+ matrix_test_double();
+ dlog << LINFO << "begin testing with float";
+ matrix_test_float();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/matrix_qr.cpp b/ml/dlib/dlib/test/matrix_qr.cpp
new file mode 100644
index 000000000..e3c7c4e42
--- /dev/null
+++ b/ml/dlib/dlib/test/matrix_qr.cpp
@@ -0,0 +1,208 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+#include <dlib/string.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.matrix_qr");
+
+ dlib::rand rnd;
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename mat_type>
+ const matrix<typename mat_type::type> symm(const mat_type& m) { return m*trans(m); }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename type>
+ const matrix<type> randmat(long r, long c)
+ {
+ matrix<type> m(r,c);
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = 0; col < m.nc(); ++col)
+ {
+ m(row,col) = static_cast<type>(rnd.get_random_double());
+ }
+ }
+
+ return m;
+ }
+
+ template <typename type, long NR, long NC>
+ const matrix<type,NR,NC> randmat()
+ {
+ matrix<type,NR,NC> m;
+ for (long row = 0; row < m.nr(); ++row)
+ {
+ for (long col = 0; col < m.nc(); ++col)
+ {
+ m(row,col) = static_cast<type>(rnd.get_random_double());
+ }
+ }
+
+ return m;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename matrix_type>
+ void test_qr ( const matrix_type& m)
+ {
+ typedef typename matrix_type::type type;
+ const type eps = 10*max(abs(m))*sqrt(std::numeric_limits<type>::epsilon());
+ dlog << LDEBUG << "test_qr(): " << m.nr() << " x " << m.nc() << " eps: " << eps;
+ print_spinner();
+
+
+ qr_decomposition<matrix_type> test(m);
+
+
+ DLIB_TEST(test.nr() == m.nr());
+ DLIB_TEST(test.nc() == m.nc());
+
+
+ type temp;
+ DLIB_TEST_MSG( (temp= max(abs(test.get_q()*test.get_r() - m))) < eps,temp);
+
+ // none of the matrices we should be passing in to test_qr() should be non-full rank.
+ DLIB_TEST(test.is_full_rank() == true);
+
+ if (m.nr() == m.nc())
+ {
+ matrix<type> m2;
+ matrix<type,0,1> col;
+
+ m2 = identity_matrix<type>(m.nr());
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ m2 = randmat<type>(m.nr(),5);
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ m2 = randmat<type>(m.nr(),1);
+ DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
+ col = randmat<type>(m.nr(),1);
+ DLIB_TEST_MSG(equal(m*test.solve(col), col,eps),max(abs(m*test.solve(m2)- m2)));
+ }
+ else
+ {
+ DLIB_TEST_MSG(dlib::equal(pinv(m), test.solve(identity_matrix<type>(m.nr())), eps),
+ max(abs(pinv(m) - test.solve(identity_matrix<type>(m.nr())))) );
+ }
+
+ // now make us a non-full rank matrix
+ if (m.nc() > 1)
+ {
+ matrix<type> sm(m);
+ set_colm(sm,0) = colm(sm,1);
+
+ qr_decomposition<matrix_type> test2(sm);
+ DLIB_TEST_MSG( (temp= max(abs(test.get_q()*test.get_r() - m))) < eps,temp);
+
+ if (test2.nc() < 100)
+ {
+ DLIB_TEST_MSG(test2.is_full_rank() == false,"eps: " << eps);
+ }
+
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void matrix_test_double()
+ {
+
+ test_qr(10*randmat<double>(1,1));
+ test_qr(10*randmat<double>(2,2));
+ test_qr(10*symm(randmat<double>(2,2)));
+ test_qr(10*randmat<double>(4,4));
+ test_qr(10*randmat<double>(9,4));
+ test_qr(10*randmat<double>(15,15));
+ test_qr(2*symm(randmat<double>(15,15)));
+ test_qr(10*randmat<double>(100,100));
+ test_qr(10*randmat<double>(237,200));
+ test_qr(10*randmat<double>(200,101));
+
+ test_qr(10*randmat<double,1,1>());
+ test_qr(10*randmat<double,2,2>());
+ test_qr(10*randmat<double,4,3>());
+ test_qr(10*randmat<double,4,4>());
+ test_qr(10*randmat<double,9,4>());
+ test_qr(10*randmat<double,15,15>());
+ test_qr(10*randmat<double,100,100>());
+
+ typedef matrix<double,0,0,default_memory_manager, column_major_layout> mat;
+ test_qr(mat(3*randmat<double>(9,4)));
+ test_qr(mat(3*randmat<double>(9,9)));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void matrix_test_float()
+ {
+
+
+ test_qr(3*randmat<float>(1,1));
+ test_qr(3*randmat<float>(2,2));
+ test_qr(3*randmat<float>(4,4));
+ test_qr(3*randmat<float>(9,4));
+ test_qr(3*randmat<float>(237,200));
+
+ test_qr(3*randmat<float,1,1>());
+ test_qr(3*randmat<float,2,2>());
+ test_qr(3*randmat<float,4,3>());
+ test_qr(3*randmat<float,4,4>());
+ test_qr(3*randmat<float,5,4>());
+
+ typedef matrix<float,0,0,default_memory_manager, column_major_layout> mat;
+ test_qr(mat(3*randmat<float>(5,4)));
+ test_qr(mat(3*randmat<float>(9,9)));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class matrix_tester : public tester
+ {
+ public:
+ matrix_tester (
+ ) :
+ tester ("test_matrix_qr",
+ "Runs tests on the matrix QR component.")
+ {
+ //rnd.set_seed(cast_to_string(time(0)));
+ }
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "seed string: " << rnd.get_seed();
+
+ dlog << LINFO << "begin testing with double";
+ matrix_test_double();
+ dlog << LINFO << "begin testing with float";
+ matrix_test_float();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/max_cost_assignment.cpp b/ml/dlib/dlib/test/max_cost_assignment.cpp
new file mode 100644
index 000000000..852418764
--- /dev/null
+++ b/ml/dlib/dlib/test/max_cost_assignment.cpp
@@ -0,0 +1,157 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/optimization.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../rand.h"
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.max_cost_assignment");
+
+// ----------------------------------------------------------------------------------------
+
+ std::vector<std::vector<long> > permutations (
+ matrix<long,1,0> vals
+ )
+ {
+ if (vals.size() == 0)
+ {
+ return std::vector<std::vector<long> >();
+ }
+ else if (vals.size() == 1)
+ {
+ return std::vector<std::vector<long> >(1,std::vector<long>(1,vals(0)));
+ }
+
+
+ std::vector<std::vector<long> > temp;
+
+
+ for (long i = 0; i < vals.size(); ++i)
+ {
+ const std::vector<std::vector<long> >& res = permutations(remove_col(vals,i));
+
+ for (unsigned long j = 0; j < res.size(); ++j)
+ {
+ temp.resize(temp.size()+1);
+ std::vector<long>& part = temp.back();
+ part.push_back(vals(i));
+ part.insert(part.end(), res[j].begin(), res[j].end());
+ }
+ }
+
+
+ return temp;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ std::vector<long> brute_force_max_cost_assignment (
+ matrix<T> cost
+ )
+ {
+ if (cost.size() == 0)
+ return std::vector<long>();
+
+ const std::vector<std::vector<long> >& perms = permutations(range(0,cost.nc()-1));
+
+ T best_cost = std::numeric_limits<T>::min();
+ unsigned long best_idx = 0;
+ for (unsigned long i = 0; i < perms.size(); ++i)
+ {
+ const T temp = assignment_cost(cost, perms[i]);
+ if (temp > best_cost)
+ {
+ best_idx = i;
+ best_cost = temp;
+ }
+ }
+
+ return perms[best_idx];
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ class test_max_cost_assignment : public tester
+ {
+ public:
+ test_max_cost_assignment (
+ ) :
+ tester ("test_max_cost_assignment",
+ "Runs tests on the max_cost_assignment function.")
+ {}
+
+ dlib::rand rnd;
+
+ template <typename T>
+ void test_hungarian()
+ {
+ long size = rnd.get_random_32bit_number()%7;
+ long range = rnd.get_random_32bit_number()%100;
+ matrix<T> cost = matrix_cast<T>(randm(size,size,rnd)*range) - range/2;
+
+ // use a uniform cost matrix sometimes
+ if ((rnd.get_random_32bit_number()%100) == 0)
+ cost = rnd.get_random_32bit_number()%100;
+
+ // negate the cost matrix every now and then
+ if ((rnd.get_random_32bit_number()%100) == 0)
+ cost = -cost;
+
+
+ std::vector<long> assign = brute_force_max_cost_assignment(cost);
+ T true_eval = assignment_cost(cost, assign);
+ assign = max_cost_assignment(cost);
+ DLIB_TEST(assignment_cost(cost,assign) == true_eval);
+ assign = max_cost_assignment(matrix_cast<signed char>(cost));
+ DLIB_TEST(assignment_cost(cost,assign) == true_eval);
+
+
+ cost = matrix_cast<T>(randm(size,size,rnd)*range);
+ assign = brute_force_max_cost_assignment(cost);
+ true_eval = assignment_cost(cost, assign);
+ assign = max_cost_assignment(cost);
+ DLIB_TEST(assignment_cost(cost,assign) == true_eval);
+ assign = max_cost_assignment(matrix_cast<unsigned char>(cost));
+ DLIB_TEST(assignment_cost(cost,assign) == true_eval);
+ assign = max_cost_assignment(matrix_cast<typename unsigned_type<T>::type>(cost));
+ DLIB_TEST(assignment_cost(cost,assign) == true_eval);
+ }
+
+ void perform_test (
+ )
+ {
+ for (long i = 0; i < 1000; ++i)
+ {
+ if ((i%100) == 0)
+ print_spinner();
+
+ test_hungarian<short>();
+ test_hungarian<int>();
+ test_hungarian<long>();
+ test_hungarian<int64>();
+ }
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/max_sum_submatrix.cpp b/ml/dlib/dlib/test/max_sum_submatrix.cpp
new file mode 100644
index 000000000..34b4756ff
--- /dev/null
+++ b/ml/dlib/dlib/test/max_sum_submatrix.cpp
@@ -0,0 +1,177 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/optimization.h>
+#include <dlib/rand.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.max_sum_submatrix");
+
+// ----------------------------------------------------------------------------------------
+
+ bool order_rects (
+ const rectangle& a,
+ const rectangle& b
+ )
+ {
+ if (a.left() < b.left()) return true;
+ else if (a.left() > b.left()) return false;
+
+ if (a.right() < b.right()) return true;
+ else if (a.right() > b.right()) return false;
+
+ if (a.top() < b.top()) return true;
+ else if (a.top() > b.top()) return false;
+
+ if (a.bottom() < b.bottom()) return true;
+ else if (a.bottom() > b.bottom()) return false;
+
+ return false;
+ }
+
+ void run_test(
+ const int num
+ )
+ {
+ static dlib::rand rnd;
+
+ matrix<int> mat, mask;
+
+ mat.set_size(rnd.get_random_32bit_number()%1000 + 1,
+ rnd.get_random_32bit_number()%1000 + 1);
+ mask.set_size(mat.nr(), mat.nc());
+ mask = 0;
+
+ mat = -10000;
+
+ std::vector<rectangle> true_rects;
+
+ for (int i = 0; i < num; ++i)
+ {
+ const int width = rnd.get_random_32bit_number()%100 + 1;
+ const int height = rnd.get_random_32bit_number()%100 + 1;
+
+ rectangle rect = centered_rect(rnd.get_random_16bit_number()%mat.nc(),
+ rnd.get_random_16bit_number()%mat.nr(),
+ width,height);
+ rect = get_rect(mat).intersect(rect);
+
+ // make sure this new rectangle doesn't overlap or abut any others
+ if (sum(subm(mask,grow_rect(rect,1).intersect(get_rect(mask)))) == 0)
+ {
+ set_subm(mat, rect) = rnd.get_random_8bit_number()%100 + 1;
+ set_subm(mask, rect) = 1;
+ true_rects.push_back(rect);
+ }
+ }
+
+
+ std::vector<rectangle> res;
+ res = max_sum_submatrix(mat, true_rects.size()+10, 0);
+
+ DLIB_TEST(res.size() == true_rects.size());
+
+ // make sure big rectangles come first
+ for (unsigned long i = 0; i+1 < res.size(); ++i)
+ {
+ DLIB_TEST(sum(subm(mat,res[i])) >= sum(subm(mat,res[i+1])));
+ }
+
+ // make sure rectangles match
+ sort(true_rects.begin(), true_rects.end(), order_rects);
+ sort(res.begin(), res.end(), order_rects);
+ for (unsigned long i = 0; i < res.size(); ++i)
+ {
+ DLIB_TEST_MSG(res[i] == true_rects[i],
+ "i: " << i << " res[i]: " << res[i] << " true_rects[i]: " << true_rects[i]);
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ void run_test2()
+ {
+ matrix<T> mat(100,100);
+ mat = 1;
+ std::vector<rectangle> res = max_sum_submatrix(mat, 0, 0);
+
+ DLIB_TEST(res.size() == 0);
+ res = max_sum_submatrix(mat, 1, 0);
+ DLIB_TEST(res.size() == 1);
+ DLIB_TEST(res[0] == get_rect(mat));
+ res = max_sum_submatrix(mat, 3, 0);
+ DLIB_TEST(res.size() == 1);
+ DLIB_TEST(res[0] == get_rect(mat));
+ res = max_sum_submatrix(mat, 3, 10);
+ DLIB_TEST(res.size() == 1);
+ DLIB_TEST(res[0] == get_rect(mat));
+
+ res = max_sum_submatrix(mat, 3, mat.size());
+ DLIB_TEST(res.size() == 0);
+
+ mat = -1;
+ res = max_sum_submatrix(mat, 1, 0);
+ DLIB_TEST(res.size() == 0);
+
+ const rectangle rect1 = rectangle(10,10,40,40);
+ const rectangle rect2 = rectangle(35,35,80,80);
+
+ set_subm(mat, rect1) = 2;
+ set_subm(mat, rect2) = 1;
+ res = max_sum_submatrix(mat, 3, 0);
+ DLIB_TEST(res.size() == 2);
+ DLIB_TEST(res[0] == rect2);
+ DLIB_TEST(res[1] == rect1);
+
+ res = max_sum_submatrix(mat, 3, 2*rect1.area() - 2*(rect1.intersect(rect2)).area());
+ DLIB_TEST(res.size() == 1);
+ DLIB_TEST(res[0] == rect2);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+
+ class test_max_sum_submatrix : public tester
+ {
+ public:
+ test_max_sum_submatrix (
+ ) :
+ tester ("test_max_sum_submatrix",
+ "Runs tests on the max_sum_submatrix() function.")
+ {}
+
+ void perform_test (
+ )
+ {
+ for (int j = 0; j < 5; ++j)
+ {
+ print_spinner();
+ for (int i = 0; i < 40; ++i)
+ run_test(i);
+ }
+
+ run_test2<int>();
+ run_test2<short>();
+ run_test2<signed char>();
+ run_test2<float>();
+ run_test2<double>();
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/md5.cpp b/ml/dlib/dlib/test/md5.cpp
new file mode 100644
index 000000000..15fafac3c
--- /dev/null
+++ b/ml/dlib/dlib/test/md5.cpp
@@ -0,0 +1,71 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/md5.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.md5");
+
+ void md5_test (
+ )
+ /*!
+ ensures
+ - runs tests on the md5 stuff compliance with the specs
+ !*/
+ {
+
+ DLIB_TEST(md5 ("") == "d41d8cd98f00b204e9800998ecf8427e");
+ DLIB_TEST(md5 ("a") == "0cc175b9c0f1b6a831c399e269772661");
+ DLIB_TEST(md5 ("abc") == "900150983cd24fb0d6963f7d28e17f72");
+ DLIB_TEST(md5 ("message digest") == "f96b697d7cb7938d525a2f31aaf161d0");
+ DLIB_TEST(md5 ("abcdefghijklmnopqrstuvwxyz") == "c3fcd3d76192e4007dfb496cca67e13b");
+ DLIB_TEST(md5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") == "d174ab98d277d9f5a5611c2c9f419d9f");
+ DLIB_TEST(md5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") == "57edf4a22be3c955ac49da2e2107b67a");
+
+ // make sure the two versions of md5() always agree
+ for (int num = 0; num < 2000; ++num)
+ {
+ std::string temp;
+ for (int i = 0; i < num; ++i)
+ temp += 'a';
+
+ istringstream str(temp);
+ DLIB_TEST(md5(temp) == md5(str));
+ }
+
+ }
+
+
+ class md5_tester : public tester
+ {
+ public:
+ md5_tester (
+ ) :
+ tester ("test_md5",
+ "Runs tests on the md5 component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ md5_test();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/member_function_pointer.cpp b/ml/dlib/dlib/test/member_function_pointer.cpp
new file mode 100644
index 000000000..72aa3aa35
--- /dev/null
+++ b/ml/dlib/dlib/test/member_function_pointer.cpp
@@ -0,0 +1,553 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/member_function_pointer.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.member_function_pointer");
+
+ class mfp_test_helper_other
+ {
+ public:
+ mfp_test_helper_other (
+ ): i(-1) {}
+
+
+ mutable int i;
+
+
+ void go0 (
+ ) { i = 0; }
+ void go1 (
+ int v1
+ ) { i = 1*v1; }
+ void go2 (
+ int v1,int v2
+ ) { i = 2*v1*v2; }
+ void go3 (
+ int v1,int v2,int v3
+ ) { i = 3*v1*v2*v3; }
+ void go4 (
+ int v1,int v2,int v3,int v4
+ ) { i = 4*v1*v2*v3*v4; }
+
+ };
+
+
+ class mfp_test_helper
+ {
+ public:
+ mfp_test_helper (
+ ): i(-1) {}
+
+
+ mutable int i;
+
+
+ void go0 (
+ ) { i = 0; }
+ void go1 (
+ int v1
+ ) { i = 1*v1; }
+ void go2 (
+ int v1,int v2
+ ) { i = 2*v1*v2; }
+ void go3 (
+ int v1,int v2,int v3
+ ) { i = 3*v1*v2*v3; }
+ void go4 (
+ int v1,int v2,int v3,int v4
+ ) { i = 4*v1*v2*v3*v4; }
+
+ };
+
+ class mfp_test_helper_const
+ {
+ public:
+ mfp_test_helper_const (
+ ): i(-1) {}
+
+
+ mutable int i;
+
+ void go0 (
+ ) const { i = 0; }
+ void go1 (
+ int v1
+ ) const { i = 1*v1; }
+ void go2 (
+ int v1,int v2
+ ) const { i = 2*v1*v2; }
+ void go3 (
+ int v1,int v2,int v3
+ ) const { i = 3*v1*v2*v3; }
+ void go4 (
+ int v1,int v2,int v3,int v4
+ ) const { i = 4*v1*v2*v3*v4; }
+ };
+
+ template <
+ template <typename P1 = void, typename P2 = void, typename P3 = void, typename P4 = void> class mfp,
+ typename test_helper
+ >
+ void member_function_pointer_kernel_test (
+ )
+ /*!
+ requires
+ - mfp is an implementation of member_function_pointer/member_function_pointer_kernel_abstract.h
+ ensures
+ - runs tests on mfp for compliance with the specs
+ !*/
+ {
+
+
+ test_helper helper;
+
+ mfp<> a0, b0;
+ mfp<int> a1, b1;
+ mfp<int,int> a2, b2;
+ mfp<int,int,int> a3, b3;
+ mfp<int,int,int,int> a4, b4;
+
+ mfp<> a0c, b0c;
+ mfp<int> a1c, b1c;
+ mfp<int,int> a2c, b2c;
+ mfp<int,int,int> a3c, b3c;
+ mfp<int,int,int,int> a4c, b4c;
+
+ DLIB_TEST(a0c == b0c);
+ DLIB_TEST(a1c == b1c);
+ DLIB_TEST(a2c == b2c);
+ DLIB_TEST(a3c == b3c);
+ DLIB_TEST(a4c == b4c);
+ DLIB_TEST((a0c != b0c) == false);
+ DLIB_TEST((a1c != b1c) == false);
+ DLIB_TEST((a2c != b2c) == false);
+ DLIB_TEST((a3c != b3c) == false);
+ DLIB_TEST((a4c != b4c) == false);
+
+ DLIB_TEST(a0.is_set() == false);
+ DLIB_TEST(b0.is_set() == false);
+ DLIB_TEST(a0c.is_set() == false);
+ DLIB_TEST(b0c.is_set() == false);
+
+ DLIB_TEST(!a0 );
+ DLIB_TEST(!b0 );
+ DLIB_TEST(!a0c);
+ DLIB_TEST(!b0c);
+
+ DLIB_TEST(a1.is_set() == false);
+ DLIB_TEST(b1.is_set() == false);
+ DLIB_TEST(a1c.is_set() == false);
+ DLIB_TEST(b1c.is_set() == false);
+
+ DLIB_TEST(!a1 );
+ DLIB_TEST(!b1 );
+ DLIB_TEST(!a1c);
+ DLIB_TEST(!b1c);
+
+
+ DLIB_TEST(a2.is_set() == false);
+ DLIB_TEST(b2.is_set() == false);
+ DLIB_TEST(a2c.is_set() == false);
+ DLIB_TEST(b2c.is_set() == false);
+
+ DLIB_TEST(!a2);
+ DLIB_TEST(!b2);
+ DLIB_TEST(!a2c);
+ DLIB_TEST(!b2c);
+
+ DLIB_TEST(a3.is_set() == false);
+ DLIB_TEST(b3.is_set() == false);
+ DLIB_TEST(a3c.is_set() == false);
+ DLIB_TEST(b3c.is_set() == false);
+
+ DLIB_TEST(!a3);
+ DLIB_TEST(!b3);
+ DLIB_TEST(!a3c);
+ DLIB_TEST(!b3c);
+
+ DLIB_TEST(a4.is_set() == false);
+ DLIB_TEST(b4.is_set() == false);
+ DLIB_TEST(a4c.is_set() == false);
+ DLIB_TEST(b4c.is_set() == false);
+
+ DLIB_TEST(!a4);
+ DLIB_TEST(!b4);
+ DLIB_TEST(!a4c);
+ DLIB_TEST(!b4c);
+
+ a0.set(helper,&test_helper::go0);
+ a0c.set(helper,&test_helper::go0);
+ DLIB_TEST(a0.is_set() == true);
+ DLIB_TEST(a0c.is_set() == true);
+ DLIB_TEST(b0.is_set() == false);
+ DLIB_TEST(b0c.is_set() == false);
+
+ DLIB_TEST(a0);
+ DLIB_TEST(a0c);
+ DLIB_TEST(!b0);
+ DLIB_TEST(!b0c);
+
+ a0 = a0;
+ DLIB_TEST(a0 == a0);
+ DLIB_TEST(!(a0 != a0));
+ DLIB_TEST(a0.is_set() == true);
+ DLIB_TEST(a0c.is_set() == true);
+ DLIB_TEST(b0.is_set() == false);
+ DLIB_TEST(b0c.is_set() == false);
+
+ DLIB_TEST(a0);
+ DLIB_TEST(a0c);
+ DLIB_TEST(!b0);
+ DLIB_TEST(!b0c);
+
+ swap(a0,b0);
+ swap(a0c,b0c);
+ DLIB_TEST(a0.is_set() == false);
+ DLIB_TEST(a0c.is_set() == false);
+ DLIB_TEST(b0.is_set() == true);
+ DLIB_TEST(b0c.is_set() == true);
+
+ DLIB_TEST(!a0);
+ DLIB_TEST(!a0c);
+ DLIB_TEST(b0);
+ DLIB_TEST(b0c);
+
+ a0 = b0;
+ DLIB_TEST(a0 == a0);
+ DLIB_TEST(a0 == b0);
+ DLIB_TEST(!(a0 != b0));
+ DLIB_TEST(a0.is_set() == true);
+ DLIB_TEST(a0c.is_set() == false);
+ DLIB_TEST(b0.is_set() == true);
+ DLIB_TEST(b0c.is_set() == true);
+
+ DLIB_TEST(a0 );
+ DLIB_TEST(!a0c);
+ DLIB_TEST(b0);
+ DLIB_TEST(b0c);
+
+
+ a0.clear();
+ a0c.clear();
+ b0.clear();
+ b0c.clear();
+ DLIB_TEST(a0.is_set() == false);
+ DLIB_TEST(a0c.is_set() == false);
+ DLIB_TEST(b0.is_set() == false);
+ DLIB_TEST(b0c.is_set() == false);
+
+
+ a1.set(helper,&test_helper::go1);
+ a1c.set(helper,&test_helper::go1);
+ DLIB_TEST(a1.is_set() == true);
+ DLIB_TEST(a1c.is_set() == true);
+ DLIB_TEST(b1.is_set() == false);
+ DLIB_TEST(b1c.is_set() == false);
+ swap(a1,b1);
+ swap(a1c,b1c);
+ DLIB_TEST(a1.is_set() == false);
+ DLIB_TEST(a1c.is_set() == false);
+ DLIB_TEST(b1.is_set() == true);
+ DLIB_TEST(b1c.is_set() == true);
+
+ DLIB_TEST(!a1);
+ DLIB_TEST(!a1c);
+ DLIB_TEST(b1);
+ DLIB_TEST(b1c);
+
+
+ a1 = b1;
+ DLIB_TEST(a1 == a1);
+ DLIB_TEST(a1 == b1);
+ DLIB_TEST(!(a1 != b1));
+ DLIB_TEST(a1.is_set() == true);
+ DLIB_TEST(a1c.is_set() == false);
+ DLIB_TEST(b1.is_set() == true);
+ DLIB_TEST(b1c.is_set() == true);
+
+
+ a1.clear();
+ a1c.clear();
+ b1.clear();
+ b1c.clear();
+ DLIB_TEST(a1.is_set() == false);
+ DLIB_TEST(a1c.is_set() == false);
+ DLIB_TEST(b1.is_set() == false);
+ DLIB_TEST(b1c.is_set() == false);
+
+
+ a2.set(helper,&test_helper::go2);
+ a2c.set(helper,&test_helper::go2);
+ DLIB_TEST(a2.is_set() == true);
+ DLIB_TEST(a2c.is_set() == true);
+ DLIB_TEST(b2.is_set() == false);
+ DLIB_TEST(b2c.is_set() == false);
+ swap(a2,b2);
+ swap(a2c,b2c);
+ DLIB_TEST(a2.is_set() == false);
+ DLIB_TEST(a2c.is_set() == false);
+ DLIB_TEST(b2.is_set() == true);
+ DLIB_TEST(b2c.is_set() == true);
+
+ DLIB_TEST(!a2);
+ DLIB_TEST(!a2c);
+ DLIB_TEST(b2);
+ DLIB_TEST(b2c);
+ if (b2)
+ {
+ }
+ else
+ {
+ DLIB_TEST(false);
+ }
+
+ if (a2c)
+ {
+ DLIB_TEST(false);
+ }
+ else
+ {
+ DLIB_TEST(true);
+ }
+
+ a2 = b2;
+ DLIB_TEST(a2 == a2);
+ DLIB_TEST(a2 == b2);
+ DLIB_TEST(!(a2 != b2));
+ DLIB_TEST(a2.is_set() == true);
+ DLIB_TEST(a2c.is_set() == false);
+ DLIB_TEST(b2.is_set() == true);
+ DLIB_TEST(b2c.is_set() == true);
+
+ a2.clear();
+ a2c.clear();
+ b2.clear();
+ b2c.clear();
+ DLIB_TEST(a2.is_set() == false);
+ DLIB_TEST(a2c.is_set() == false);
+ DLIB_TEST(b2.is_set() == false);
+ DLIB_TEST(b2c.is_set() == false);
+
+
+ a3.set(helper,&test_helper::go3);
+ a3c.set(helper,&test_helper::go3);
+ DLIB_TEST(a3.is_set() == true);
+ DLIB_TEST(a3c.is_set() == true);
+ DLIB_TEST(b3.is_set() == false);
+ DLIB_TEST(b3c.is_set() == false);
+ swap(a3,b3);
+ swap(a3c,b3c);
+ DLIB_TEST(a3.is_set() == false);
+ DLIB_TEST(a3c.is_set() == false);
+ DLIB_TEST(b3.is_set() == true);
+ DLIB_TEST(b3c.is_set() == true);
+
+ a3 = b3;
+ DLIB_TEST(a3 == a3);
+ DLIB_TEST(a3 == b3);
+ DLIB_TEST(!(a3 != b3));
+ DLIB_TEST(a3.is_set() == true);
+ DLIB_TEST(a3c.is_set() == false);
+ DLIB_TEST(b3.is_set() == true);
+ DLIB_TEST(b3c.is_set() == true);
+
+
+ a3.clear();
+ a3c.clear();
+ b3.clear();
+ b3c.clear();
+ DLIB_TEST(a3.is_set() == false);
+ DLIB_TEST(a3c.is_set() == false);
+ DLIB_TEST(b3.is_set() == false);
+ DLIB_TEST(b3c.is_set() == false);
+
+
+ a4.set(helper,&test_helper::go4);
+ a4c.set(helper,&test_helper::go4);
+ DLIB_TEST(a4.is_set() == true);
+ DLIB_TEST(a4c.is_set() == true);
+ DLIB_TEST(b4.is_set() == false);
+ DLIB_TEST(b4c.is_set() == false);
+ swap(a4,b4);
+ swap(a4c,b4c);
+ DLIB_TEST(a4.is_set() == false);
+ DLIB_TEST(a4c.is_set() == false);
+ DLIB_TEST(b4.is_set() == true);
+ DLIB_TEST(b4c.is_set() == true);
+
+ a4 = b4;
+ a4 = b4;
+ a4 = b4;
+ a4 = b4;
+ DLIB_TEST(a4 == a4);
+ DLIB_TEST(a4 == b4);
+ DLIB_TEST(!(a4 != b4));
+ DLIB_TEST(a4.is_set() == true);
+ DLIB_TEST(a4c.is_set() == false);
+ DLIB_TEST(b4.is_set() == true);
+ DLIB_TEST(b4c.is_set() == true);
+
+
+ a4.clear();
+ a4c.clear();
+ b4.clear();
+ b4c.clear();
+ DLIB_TEST(a4.is_set() == false);
+ DLIB_TEST(a4c.is_set() == false);
+ DLIB_TEST(b4.is_set() == false);
+ DLIB_TEST(b4c.is_set() == false);
+
+
+ a0.set(helper,&test_helper::go0);
+ a0c.set(helper,&test_helper::go0);
+ b0 = a0;
+ b0c = a0c;
+ helper.i = -1;
+ a0();
+ DLIB_TEST(helper.i == 0);
+ helper.i = -1;
+ b0();
+ DLIB_TEST(helper.i == 0);
+ helper.i = -1;
+ a0c();
+ DLIB_TEST(helper.i == 0);
+ helper.i = -1;
+ b0c();
+ DLIB_TEST(helper.i == 0);
+
+
+ a1.set(helper,&test_helper::go1);
+ a1c.set(helper,&test_helper::go1);
+ b1 = a1;
+ b1c = a1c;
+ helper.i = -1;
+ a1(1);
+ DLIB_TEST(helper.i == 1);
+ helper.i = -1;
+ b1(10);
+ DLIB_TEST(helper.i == 1*10);
+ helper.i = -1;
+ a1c(20);
+ DLIB_TEST(helper.i == 1*20);
+ helper.i = -1;
+ b1c(30);
+ DLIB_TEST(helper.i == 1*30);
+
+
+ a2.set(helper,&test_helper::go2);
+ a2c.set(helper,&test_helper::go2);
+ b2 = a2;
+ b2c = a2c;
+ helper.i = -1;
+ a2(1,2);
+ DLIB_TEST(helper.i == 2*1*2);
+ helper.i = -1;
+ b2(3,4);
+ DLIB_TEST(helper.i == 2*3*4);
+ helper.i = -1;
+ a2c(5,6);
+ DLIB_TEST(helper.i == 2*5*6);
+ helper.i = -1;
+ b2c(7,8);
+ DLIB_TEST(helper.i == 2*7*8);
+
+
+ a3.set(helper,&test_helper::go3);
+ a3c.set(helper,&test_helper::go3);
+ b3 = a3;
+ b3c = a3c;
+ helper.i = -1;
+ a3(1,2,3);
+ DLIB_TEST(helper.i == 3*1*2*3);
+ helper.i = -1;
+ b3(4,5,6);
+ DLIB_TEST(helper.i == 3*4*5*6);
+ helper.i = -1;
+ a3c(7,8,9);
+ DLIB_TEST(helper.i == 3*7*8*9);
+ helper.i = -1;
+ b3c(1,2,3);
+ DLIB_TEST(helper.i == 3*1*2*3);
+
+
+ a4.set(helper,&test_helper::go4);
+ a4c.set(helper,&test_helper::go4);
+ DLIB_TEST(a4 == a4c);
+ b4 = a4;
+ b4c = a4c;
+ helper.i = -1;
+ a4(1,2,3,4);
+ DLIB_TEST(helper.i == 4*1*2*3*4);
+ helper.i = -1;
+ b4(5,6,7,8);
+ DLIB_TEST(helper.i == 4*5*6*7*8);
+ helper.i = -1;
+ a4c(9,1,2,3);
+ DLIB_TEST(helper.i == 4*9*1*2*3);
+ helper.i = -1;
+ b4c(4,5,6,7);
+ DLIB_TEST(helper.i == 4*4*5*6*7);
+
+ DLIB_TEST(a4 == b4);
+ DLIB_TEST(a4);
+ DLIB_TEST(a4 == b4);
+ a4.clear();
+ DLIB_TEST(a4 != b4);
+ DLIB_TEST(!a4);
+ DLIB_TEST(a4 == 0);
+ DLIB_TEST(a4 == a4);
+ a4 = a4;
+ DLIB_TEST(a4 != b4);
+ DLIB_TEST(!a4);
+ DLIB_TEST(a4 == a4);
+ mfp_test_helper_other other;
+ a4.set(other,&mfp_test_helper_other::go4);
+ DLIB_TEST(a4 != b4);
+ DLIB_TEST(a4);
+ DLIB_TEST(a4 == a4);
+ a4.set(helper,&test_helper::go4);
+ DLIB_TEST(a4 == b4);
+ DLIB_TEST(a4);
+ DLIB_TEST(a4 == a4);
+
+
+
+ }
+
+
+
+ class member_function_pointer_tester : public tester
+ {
+ public:
+ member_function_pointer_tester (
+ ) :
+ tester ("test_member_function_pointer",
+ "Runs tests on the member_function_pointer component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ member_function_pointer_kernel_test<member_function_pointer,mfp_test_helper>();
+ member_function_pointer_kernel_test<member_function_pointer,mfp_test_helper_const>();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/metaprogramming.cpp b/ml/dlib/dlib/test/metaprogramming.cpp
new file mode 100644
index 000000000..344d5ca3a
--- /dev/null
+++ b/ml/dlib/dlib/test/metaprogramming.cpp
@@ -0,0 +1,94 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/algs.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.metaprogramming");
+
+
+ void metaprogramming_test (
+ )
+ /*!
+ ensures
+ - runs tests on template metaprogramming objects and functions for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ DLIB_TEST(is_signed_type<signed char>::value == true);
+ DLIB_TEST(is_signed_type<signed short>::value == true);
+ DLIB_TEST(is_signed_type<signed int>::value == true);
+ DLIB_TEST(is_signed_type<signed long>::value == true);
+ DLIB_TEST(is_unsigned_type<signed char>::value == false);
+ DLIB_TEST(is_unsigned_type<signed short>::value == false);
+ DLIB_TEST(is_unsigned_type<signed int>::value == false);
+ DLIB_TEST(is_unsigned_type<signed long>::value == false);
+
+ DLIB_TEST(is_unsigned_type<unsigned char>::value == true);
+ DLIB_TEST(is_unsigned_type<unsigned short>::value == true);
+ DLIB_TEST(is_unsigned_type<unsigned int>::value == true);
+ DLIB_TEST(is_unsigned_type<unsigned long>::value == true);
+ DLIB_TEST(is_signed_type<unsigned char>::value == false);
+ DLIB_TEST(is_signed_type<unsigned short>::value == false);
+ DLIB_TEST(is_signed_type<unsigned int>::value == false);
+ DLIB_TEST(is_signed_type<unsigned long>::value == false);
+
+
+ COMPILE_TIME_ASSERT(is_signed_type<signed char>::value == true);
+ COMPILE_TIME_ASSERT(is_signed_type<signed short>::value == true);
+ COMPILE_TIME_ASSERT(is_signed_type<signed int>::value == true);
+ COMPILE_TIME_ASSERT(is_signed_type<signed long>::value == true);
+ COMPILE_TIME_ASSERT(is_unsigned_type<signed char>::value == false);
+ COMPILE_TIME_ASSERT(is_unsigned_type<signed short>::value == false);
+ COMPILE_TIME_ASSERT(is_unsigned_type<signed int>::value == false);
+ COMPILE_TIME_ASSERT(is_unsigned_type<signed long>::value == false);
+
+ COMPILE_TIME_ASSERT(is_unsigned_type<unsigned char>::value == true);
+ COMPILE_TIME_ASSERT(is_unsigned_type<unsigned short>::value == true);
+ COMPILE_TIME_ASSERT(is_unsigned_type<unsigned int>::value == true);
+ COMPILE_TIME_ASSERT(is_unsigned_type<unsigned long>::value == true);
+ COMPILE_TIME_ASSERT(is_signed_type<unsigned char>::value == false);
+ COMPILE_TIME_ASSERT(is_signed_type<unsigned short>::value == false);
+ COMPILE_TIME_ASSERT(is_signed_type<unsigned int>::value == false);
+ COMPILE_TIME_ASSERT(is_signed_type<unsigned long>::value == false);
+
+
+ }
+
+
+
+
+ class metaprogramming_tester : public tester
+ {
+ public:
+ metaprogramming_tester (
+ ) :
+ tester ("test_metaprogramming",
+ "Runs tests on the metaprogramming objects and functions.")
+ {}
+
+ void perform_test (
+ )
+ {
+ metaprogramming_test();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/mpc.cpp b/ml/dlib/dlib/test/mpc.cpp
new file mode 100644
index 000000000..c0a98dd17
--- /dev/null
+++ b/ml/dlib/dlib/test/mpc.cpp
@@ -0,0 +1,346 @@
+// Copyright (C) 2015 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <string>
+#include <sstream>
+
+#include <dlib/control.h>
+#include <dlib/optimization.h>
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.mpc");
+
+ template <
+ typename EXP1,
+ typename EXP2,
+ typename T, long NR, long NC, typename MM, typename L
+ >
+ unsigned long solve_qp_box_using_smo (
+ const matrix_exp<EXP1>& _Q,
+ const matrix_exp<EXP2>& _b,
+ matrix<T,NR,NC,MM,L>& alpha,
+ matrix<T,NR,NC,MM,L>& lower,
+ matrix<T,NR,NC,MM,L>& upper,
+ T eps,
+ unsigned long max_iter
+ )
+ /*!
+ ensures
+ - solves: 0.5*trans(x)*Q*x + trans(b)*x where x is box constrained.
+ !*/
+ {
+ const_temp_matrix<EXP1> Q(_Q);
+ const_temp_matrix<EXP2> b(_b);
+ //cout << "IN QP SOLVER" << endl;
+ //cout << "max eig: " << max(real_eigenvalues(Q)) << endl;
+ //cout << "min eig: " << min(real_eigenvalues(Q)) << endl;
+ //cout << "Q: \n" << Q << endl;
+ //cout << "b: \n" << b << endl;
+
+ // make sure requires clause is not broken
+ DLIB_ASSERT(Q.nr() == Q.nc() &&
+ alpha.size() == lower.size() &&
+ alpha.size() == upper.size() &&
+ is_col_vector(b) &&
+ is_col_vector(alpha) &&
+ is_col_vector(lower) &&
+ is_col_vector(upper) &&
+ b.size() == alpha.size() &&
+ b.size() == Q.nr() &&
+ alpha.size() > 0 &&
+ 0 <= min(alpha-lower) &&
+ 0 <= max(upper-alpha) &&
+ eps > 0 &&
+ max_iter > 0,
+ "\t unsigned long solve_qp_box_using_smo()"
+ << "\n\t Invalid arguments were given to this function"
+ << "\n\t Q.nr(): " << Q.nr()
+ << "\n\t Q.nc(): " << Q.nc()
+ << "\n\t is_col_vector(b): " << is_col_vector(b)
+ << "\n\t is_col_vector(alpha): " << is_col_vector(alpha)
+ << "\n\t is_col_vector(lower): " << is_col_vector(lower)
+ << "\n\t is_col_vector(upper): " << is_col_vector(upper)
+ << "\n\t b.size(): " << b.size()
+ << "\n\t alpha.size(): " << alpha.size()
+ << "\n\t lower.size(): " << lower.size()
+ << "\n\t upper.size(): " << upper.size()
+ << "\n\t Q.nr(): " << Q.nr()
+ << "\n\t min(alpha-lower): " << min(alpha-lower)
+ << "\n\t max(upper-alpha): " << max(upper-alpha)
+ << "\n\t eps: " << eps
+ << "\n\t max_iter: " << max_iter
+ );
+
+
+ // Compute f'(alpha) (i.e. the gradient of f(alpha)) for the current alpha.
+ matrix<T,NR,NC,MM,L> df = Q*alpha + b;
+ matrix<T,NR,NC,MM,L> QQ = reciprocal_max(diag(Q));
+
+
+ unsigned long iter = 0;
+ for (; iter < max_iter; ++iter)
+ {
+ T max_df = 0;
+ long best_r =0;
+ for (long r = 0; r < Q.nr(); ++r)
+ {
+ if (alpha(r) <= lower(r) && df(r) > 0)
+ ;//alpha(r) = lower(r);
+ else if (alpha(r) >= upper(r) && df(r) < 0)
+ ;//alpha(r) = upper(r);
+ else if (std::abs(df(r)) > max_df)
+ {
+ best_r = r;
+ max_df = std::abs(df(r));
+ }
+ }
+
+ //for (long r = 0; r < Q.nr(); ++r)
+ long r = best_r;
+ {
+
+ const T old_alpha = alpha(r);
+ alpha(r) = -(df(r)-Q(r,r)*alpha(r))*QQ(r);
+ if (alpha(r) < lower(r))
+ alpha(r) = lower(r);
+ else if (alpha(r) > upper(r))
+ alpha(r) = upper(r);
+
+ const T delta = old_alpha-alpha(r);
+
+ // Now update the gradient. We will perform the equivalent of: df = Q*alpha + b;
+ for(long k = 0; k < df.nr(); ++k)
+ df(k) -= Q(r,k)*delta;
+ }
+
+ if (max_df < eps)
+ break;
+ }
+ //cout << "df: \n" << trans(df) << endl;
+ //cout << "objective value: " << 0.5*trans(alpha)*Q*alpha + trans(b)*alpha << endl;
+
+ return iter+1;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ namespace impl_mpc
+ {
+ template <long N>
+ void pack(
+ matrix<double,0,1>& out,
+ const std::vector<matrix<double,N,1> >& item
+ )
+ {
+ DLIB_CASSERT(item.size() != 0,"");
+ out.set_size(item.size()*item[0].size());
+ long j = 0;
+ for (unsigned long i = 0; i < item.size(); ++i)
+ for (long r = 0; r < item[i].size(); ++r)
+ out(j++) = item[i](r);
+ }
+
+ template <long N>
+ void pack(
+ matrix<double,0,1>& out,
+ const matrix<double,N,1>& item,
+ const long num
+ )
+ {
+ out.set_size(item.size()*num);
+ long j = 0;
+ for (long r = 0; r < num; ++r)
+ for (long i = 0; i < item.size(); ++i)
+ out(j++) = item(i);
+ }
+
+ template <long N>
+ void unpack(
+ std::vector<matrix<double,N,1> >& out,
+ const matrix<double,0,1>& item
+ )
+ {
+ DLIB_CASSERT(out.size() != 0,"");
+ DLIB_CASSERT((long)out.size()*out[0].size() == item.size(),"");
+ long j = 0;
+ for (unsigned long i = 0; i < out.size(); ++i)
+ for (long r = 0; r < out[i].size(); ++r)
+ out[i](r) = item(j++);
+ }
+ }
+
+ template <long S, long I>
+ unsigned long solve_linear_mpc (
+ const matrix<double,S,S>& A,
+ const matrix<double,S,I>& B,
+ const matrix<double,S,1>& C,
+ const matrix<double,S,1>& Q,
+ const matrix<double,I,1>& R,
+ const matrix<double,I,1>& _lower,
+ const matrix<double,I,1>& _upper,
+ const std::vector<matrix<double,S,1> >& target,
+ const matrix<double,S,1>& initial_state,
+ std::vector<matrix<double,I,1> >& controls // input and output
+ )
+ {
+ using namespace impl_mpc;
+ DLIB_CASSERT(target.size() == controls.size(),"");
+
+ matrix<double> K(B.nr()*controls.size(), B.nc()*controls.size());
+ matrix<double,0,1> M(B.nr()*controls.size());
+
+ // compute powers of A: Apow[i] == A^i
+ std::vector<matrix<double,S,S> > Apow(controls.size());
+ Apow[0] = identity_matrix(A);
+ for (unsigned long i = 1; i < Apow.size(); ++i)
+ Apow[i] = A*Apow[i-1];
+
+ // fill in K
+ K = 0;
+ for (unsigned long r = 0; r < controls.size(); ++r)
+ for (unsigned long c = 0; c <= r; ++c)
+ set_subm(K,r*B.nr(),c*B.nc(), B.nr(), B.nc()) = Apow[r-c]*B;
+
+ // fill in M
+ set_subm(M,0*A.nr(),0,A.nr(),1) = A*initial_state + C;
+ for (unsigned long i = 1; i < controls.size(); ++i)
+ set_subm(M,i*A.nr(),0,A.nr(),1) = A*subm(M,(i-1)*A.nr(),0,A.nr(),1) + C;
+
+ //cout << "M: \n" << M << endl;
+ //cout << "K: \n" << K << endl;
+
+ matrix<double,0,1> t, v, lower, upper;
+ pack(t, target);
+ pack(v, controls);
+ pack(lower, _lower, controls.size());
+ pack(upper, _upper, controls.size());
+
+
+ matrix<double> QQ(K.nr(),K.nr()), RR(K.nc(),K.nc());
+ QQ = 0;
+ RR = 0;
+ for (unsigned long c = 0; c < controls.size(); ++c)
+ {
+ set_subm(QQ,c*Q.nr(),c*Q.nr(),Q.nr(),Q.nr()) = diagm(Q);
+ set_subm(RR,c*R.nr(),c*R.nr(),R.nr(),R.nr()) = diagm(R);
+ }
+
+ matrix<double> m1 = trans(K)*QQ*K+RR;
+ matrix<double> m2 = trans(K)*QQ*(M-t);
+
+
+ // run the solver...
+ unsigned long iter;
+ iter = solve_qp_box_using_smo(
+ m1,
+ m2,
+ v,
+ lower,
+ upper,
+ 0.00000001,
+ 100000);
+
+ //cout << "iterations: " << iter << endl;
+
+ unpack(controls, v);
+ return iter;
+ }
+
+
+
+ class test_mpc : public tester
+ {
+ public:
+ test_mpc (
+ ) :
+ tester ("test_mpc",
+ "Runs tests on the mpc object.")
+ {}
+
+ void perform_test (
+ )
+ {
+ // a basic position + velocity model
+ matrix<double,2,2> A;
+ A = 1, 1,
+ 0, 1;
+ matrix<double,2,1> B, C;
+ B = 0,
+ 1;
+
+ C = 0.02,0.1; // no constant bias
+
+ matrix<double,2,1> Q;
+ Q = 2, 0; // only care about getting the position right
+ matrix<double,1,1> R, lower, upper;
+ R = 1;
+
+ lower = -0.2;
+ upper = 0.2;
+
+ std::vector<matrix<double,1,1> > controls(30);
+ std::vector<matrix<double,2,1> > target(30);
+ for (unsigned long i = 0; i < controls.size(); ++i)
+ {
+ controls[i] = 0;
+ target[i] = 0;
+ }
+
+ mpc<2,1,30> solver(A,B,C,Q,R,lower,upper);
+ solver.set_epsilon(0.00000001);
+ solver.set_max_iterations(10000);
+ matrix<double,2,1> initial_state;
+ initial_state = 0;
+ initial_state(0) = 5;
+ for (int i = 0; i < 30; ++i)
+ {
+ print_spinner();
+ matrix<double,1,1> control = solver(initial_state);
+
+ for (unsigned long i = 1; i < controls.size(); ++i)
+ controls[i-1] = controls[i];
+
+ // Compute the correct control via SMO and make sure it matches.
+ solve_linear_mpc(A,B,C,Q,R,lower,upper, target, initial_state, controls);
+ dlog << LINFO << "ERROR: " << length(control-controls[0]);
+ DLIB_TEST(length(control-controls[0]) < 1e-7);
+
+ initial_state = A*initial_state + B*control + C;
+ //cout << control(0) << "\t" << trans(initial_state);
+ }
+
+ {
+ // also just generally test our QP solver.
+ matrix<double,20,20> Q = gaussian_randm(20,20,5);
+ Q = Q*trans(Q);
+
+ matrix<double,20,1> b = randm(20,1)-0.5;
+ matrix<double,20,1> alpha, lower, upper, alpha2;
+ alpha = 0;
+ alpha2 = 0;
+ lower = -4;
+ upper = 3;
+
+ solve_qp_box_using_smo(Q,b,alpha,lower, upper, 0.000000001, 500000);
+ solve_qp_box_constrained(Q,b,alpha2,lower, upper, 0.000000001, 50000);
+ dlog << LINFO << trans(alpha);
+ dlog << LINFO << trans(alpha2);
+ dlog << LINFO << "objective value: " << 0.5*trans(alpha)*Q*alpha + trans(b)*alpha;
+ dlog << LINFO << "objective value2: " << 0.5*trans(alpha2)*Q*alpha + trans(b)*alpha2;
+ DLIB_TEST_MSG(max(abs(alpha-alpha2)) < 1e-7, max(abs(alpha-alpha2)));
+ }
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/multithreaded_object.cpp b/ml/dlib/dlib/test/multithreaded_object.cpp
new file mode 100644
index 000000000..96f8ea26e
--- /dev/null
+++ b/ml/dlib/dlib/test/multithreaded_object.cpp
@@ -0,0 +1,321 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <string>
+#include <sstream>
+
+#include <dlib/threads.h>
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.multithreaded_object");
+
+ dlib::mutex cm;
+ int count;
+
+ class test1 : multithreaded_object
+ {
+ public:
+ test1 ()
+ {
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ clear();
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ }
+
+ ~test1 ()
+ {
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ stop();
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ wait();
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ }
+
+ private:
+ };
+
+ class test2 : private multithreaded_object
+ {
+ public:
+ test2()
+ {
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ register_thread(*this,&test2::thread);
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ clear();
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ register_thread(*this,&test2::thread);
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ }
+
+ ~test2()
+ {
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ stop();
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ wait();
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ }
+
+ private:
+
+ void thread()
+ {
+ auto_mutex M(cm);
+ ++count;
+ }
+
+ };
+
+ class test3_c1 : private multithreaded_object
+ {
+ public:
+ test3_c1()
+ {
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ register_thread(*this,&test3_c1::thread);
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ start();
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(is_running() == true);
+ }
+
+ ~test3_c1()
+ {
+ DLIB_TEST(number_of_threads_registered() == 1);
+ stop();
+ DLIB_TEST(is_running() == false);
+ DLIB_TEST(number_of_threads_registered() == 1);
+ wait();
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ }
+
+ private:
+
+ void thread()
+ {
+ cm.lock();
+ ++count;
+ cm.unlock();
+ // wait until we are supposed to stop
+ while (!should_stop())
+ dlib::sleep(1);
+ }
+
+ };
+
+ class test4_c2 : private multithreaded_object
+ {
+ public:
+ test4_c2()
+ {
+ DLIB_TEST(number_of_threads_registered() == 0);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ register_thread(*this,&test4_c2::thread);
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ start();
+ DLIB_TEST(number_of_threads_registered() == 1);
+ DLIB_TEST(number_of_threads_alive() == 1);
+ DLIB_TEST(is_running() == true);
+ register_thread(*this,&test4_c2::thread);
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(number_of_threads_alive() == 2);
+ DLIB_TEST(is_running() == true);
+ start();
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(number_of_threads_alive() == 2);
+ DLIB_TEST(is_running() == true);
+ start();
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(number_of_threads_alive() == 2);
+ DLIB_TEST(is_running() == true);
+ start();
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(number_of_threads_alive() == 2);
+ DLIB_TEST(is_running() == true);
+ start();
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(number_of_threads_alive() == 2);
+ DLIB_TEST(is_running() == true);
+ pause();
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(number_of_threads_alive() == 2);
+ DLIB_TEST(is_running() == false);
+ }
+
+ ~test4_c2()
+ {
+ try
+ {
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(number_of_threads_alive() == 2);
+ DLIB_TEST_MSG(is_running() == false,"is_running(): " << is_running());
+ stop();
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(is_running() == false);
+ wait();
+ DLIB_TEST(number_of_threads_registered() == 2);
+ DLIB_TEST(number_of_threads_alive() == 0);
+ DLIB_TEST(is_running() == false);
+ }
+ catch(std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ exit(1);
+ }
+ }
+
+ private:
+
+ void thread()
+ {
+ auto_mutex M(cm);
+ ++count;
+ while (!should_stop())
+ dlib::sleep(10);
+ }
+
+ };
+
+
+ class test5 : private multithreaded_object
+ {
+ public:
+ test5()
+ {
+ register_thread(*this,&test5::thread1);
+ register_thread(*this,&test5::thread2);
+ register_thread(*this,&test5::thread3);
+ register_thread(*this,&test5::thread3);
+ start();
+ }
+
+ ~test5()
+ {
+ stop();
+ wait();
+ }
+
+ private:
+
+ void thread1()
+ {
+ while (!should_stop())
+ dlib::sleep(10);
+ }
+
+ void thread2()
+ {
+ while (!should_stop())
+ dlib::sleep(10);
+ }
+
+ void thread3()
+ {
+ while (!should_stop())
+ dlib::sleep(10);
+ }
+
+ };
+
+
+ void multithreaded_object_test (
+ )
+ /*!
+ ensures
+ - runs tests on dlib::multithreaded_object for compliance with the specs
+ !*/
+ {
+
+ count = 0;
+
+ for (int i = 0; i < 5; ++i)
+ {
+ {
+ test1 a1;
+ test2 a2;
+ test3_c1 a3;
+ test4_c2 a4;
+ test5 a5;
+ }
+ DLIB_TEST(count == (i+1)*3);
+ print_spinner();
+ }
+ count = 0;
+
+ for (int i = 0; i < 5; ++i)
+ {
+ {
+ test1 a1;
+ test2 a2;
+ test3_c1 a3;
+ test4_c2 a4;
+ test5 a5;
+ dlib::sleep(50);
+ }
+ DLIB_TEST(count == (i+1)*3);
+ print_spinner();
+ }
+ }
+
+
+ class multithreaded_object_tester : public tester
+ {
+ public:
+ multithreaded_object_tester (
+ ) :
+ tester ("test_multithreaded_object",
+ "Runs tests on the multithreaded_object component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ multithreaded_object_test();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/numerical_integration.cpp b/ml/dlib/dlib/test/numerical_integration.cpp
new file mode 100644
index 000000000..d0e247623
--- /dev/null
+++ b/ml/dlib/dlib/test/numerical_integration.cpp
@@ -0,0 +1,228 @@
+// Copyright (C) 2013 Steve Taylor (steve98654@gmail.com)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+// This function test battery is given in:
+//
+// Test functions taken from Pedro Gonnet's dissertation at ETH:
+// Adaptive Quadrature Re-Revisited
+// http://e-collection.library.ethz.ch/eserv/eth:65/eth-65-02.pdf
+
+#include <math.h>
+#include <dlib/matrix.h>
+#include <dlib/numeric_constants.h>
+#include <dlib/numerical_integration.h>
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.numerical_integration");
+
+ class numerical_integration_tester : public tester
+ {
+ public:
+ numerical_integration_tester (
+ ) :
+ tester ("test_numerical_integration",
+ "Runs tests on the numerical integration function.",
+ 0
+ )
+ {}
+
+ void perform_test()
+ {
+
+ dlog <<dlib::LINFO << "Testing integrate_function_adapt_simpson";
+
+ matrix<double,23,1> m;
+ double tol = 1e-10;
+ double eps = 1e-8;
+
+ m(0) = integrate_function_adapt_simp(&gg1, 0.0, 1.0, tol);
+ m(1) = integrate_function_adapt_simp(&gg2, 0.0, 1.0, tol);
+ m(2) = integrate_function_adapt_simp(&gg3, 0.0, 1.0, tol);
+ m(3) = integrate_function_adapt_simp(&gg4, 0.0, 1.0, tol);
+ m(4) = integrate_function_adapt_simp(&gg5, -1.0, 1.0, tol);
+ m(5) = integrate_function_adapt_simp(&gg6, 0.0, 1.0, tol);
+ m(6) = integrate_function_adapt_simp(&gg7, 0.0, 1.0, tol);
+ m(7) = integrate_function_adapt_simp(&gg8, 0.0, 1.0, tol);
+ m(8) = integrate_function_adapt_simp(&gg9, 0.0, 1.0, tol);
+ m(9) = integrate_function_adapt_simp(&gg10, 0.0, 1.0, tol);
+ m(10) = integrate_function_adapt_simp(&gg11, 0.0, 1.0, tol);
+ m(11) = integrate_function_adapt_simp(&gg12, 1e-6, 1.0, tol);
+ m(12) = integrate_function_adapt_simp(&gg13, 0.0, 10.0, tol);
+ m(13) = integrate_function_adapt_simp(&gg14, 0.0, 10.0, tol);
+ m(14) = integrate_function_adapt_simp(&gg15, 0.0, 10.0, tol);
+ m(15) = integrate_function_adapt_simp(&gg16, 0.01, 1.0, tol);
+ m(16) = integrate_function_adapt_simp(&gg17, 0.0, pi, tol);
+ m(17) = integrate_function_adapt_simp(&gg18, 0.0, 1.0, tol);
+ m(18) = integrate_function_adapt_simp(&gg19, -1.0, 1.0, tol);
+ m(19) = integrate_function_adapt_simp(&gg20, 0.0, 1.0, tol);
+ m(20) = integrate_function_adapt_simp(&gg21, 0.0, 1.0, tol);
+ m(21) = integrate_function_adapt_simp(&gg22, 0.0, 5.0, tol);
+
+ // Here we compare the approximated integrals against
+ // highly accurate approximations generated either from
+ // the exact integral values or Mathematica's NIntegrate
+ // function using a working precision of 20.
+
+ DLIB_TEST(abs(m(0) - 1.7182818284590452354) < 1e-11);
+ DLIB_TEST(abs(m(1) - 0.7000000000000000000) < eps);
+ DLIB_TEST(abs(m(2) - 0.6666666666666666667) < eps);
+ DLIB_TEST(abs(m(3) - 0.2397141133444008336) < eps);
+ DLIB_TEST(abs(m(4) - 1.5822329637296729331) < 1e-11);
+ DLIB_TEST(abs(m(5) - 0.4000000000000000000) < eps);
+ DLIB_TEST(abs(m(6) - 2.0000000000000000000) < 1e-4);
+ DLIB_TEST(abs(m(7) - 0.8669729873399110375) < eps);
+ DLIB_TEST(abs(m(8) - 1.1547005383792515290) < eps);
+ DLIB_TEST(abs(m(9) - 0.6931471805599453094) < eps);
+ DLIB_TEST(abs(m(10) - 0.3798854930417224753) < eps);
+ DLIB_TEST(abs(m(11) - 0.7775036341124982763) < eps);
+ DLIB_TEST(abs(m(12) - 0.5000000000000000000) < eps);
+ DLIB_TEST(abs(m(13) - 1.0000000000000000000) < eps);
+ DLIB_TEST(abs(m(14) - 0.4993633810764567446) < eps);
+ DLIB_TEST(abs(m(15) - 0.1121393035410217 ) < eps);
+ DLIB_TEST(abs(m(16) - 0.2910187828600526985) < eps);
+ DLIB_TEST(abs(m(17) + 0.4342944819032518276) < 1e-5);
+ DLIB_TEST(abs(m(18) - 1.56439644406905 ) < eps);
+ DLIB_TEST(abs(m(19) - 0.1634949430186372261) < eps);
+ DLIB_TEST(abs(m(20) - 0.0134924856494677726) < eps);
+ }
+
+ static double gg1(double x)
+ {
+ return pow(e,x);
+ }
+
+ static double gg2(double x)
+ {
+ if(x > 0.3)
+ {
+ return 1.0;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ static double gg3(double x)
+ {
+ return pow(x,0.5);
+ }
+
+ static double gg4(double x)
+ {
+ return 23.0/25.0*cosh(x)-cos(x);
+ }
+
+ static double gg5(double x)
+ {
+ return 1/(pow(x,4) + pow(x,2) + 0.9);
+ }
+
+ static double gg6(double x)
+ {
+ return pow(x,1.5);
+ }
+
+ static double gg7(double x)
+ {
+ return pow(x,-0.5);
+ }
+
+ static double gg8(double x)
+ {
+ return 1/(1 + pow(x,4));
+ }
+
+ static double gg9(double x)
+ {
+ return 2/(2 + sin(10*pi*x));
+ }
+
+ static double gg10(double x)
+ {
+ return 1/(1+x);
+ }
+
+ static double gg11(double x)
+ {
+ return 1.0/(1 + pow(e,x));
+ }
+
+ static double gg12(double x)
+ {
+ return x/(pow(e,x)-1.0);
+ }
+
+ static double gg13(double x)
+ {
+ return sqrt(50.0)*pow(e,-50.0*pi*x*x);
+ }
+
+ static double gg14(double x)
+ {
+ return 25.0*pow(e,-25.0*x);
+ }
+
+ static double gg15(double x)
+ {
+ return 50.0/(pi*(2500.0*x*x+1));
+ }
+
+ static double gg16(double x)
+ {
+ return 50.0*pow((sin(50.0*pi*x)/(50.0*pi*x)),2);
+ }
+
+ static double gg17(double x)
+ {
+ return cos(cos(x)+3*sin(x)+2*cos(2*x)+3*cos(3*x));
+ }
+
+ static double gg18(double x)
+ {
+ return log10(x);
+ }
+
+ static double gg19(double x)
+ {
+ return 1/(1.005+x*x);
+ }
+
+ static double gg20(double x)
+ {
+ return 1/cosh(20.0*(x-1.0/5.0)) + 1/cosh(400.0*(x-2.0/5.0))
+ + 1/cosh(8000.0*(x-3.0/5.0));
+ }
+
+ static double gg21(double x)
+ {
+ return 1.0/(1.0+(230.0*x-30.0)*(230.0*x-30.0));
+ }
+
+ static double gg22(double x)
+ {
+ if(x < 1)
+ {
+ return (x + 1.0);
+ }
+ else if(x >= 1 && x <= 3)
+ {
+ return (3.0 - x);
+ }
+ else
+ {
+ return 2.0;
+ }
+ }
+
+ };
+
+ numerical_integration_tester a;
+}
+
diff --git a/ml/dlib/dlib/test/object_detector.cpp b/ml/dlib/dlib/test/object_detector.cpp
new file mode 100644
index 000000000..fdb72f520
--- /dev/null
+++ b/ml/dlib/dlib/test/object_detector.cpp
@@ -0,0 +1,1028 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/statistics.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include "tester.h"
+#include <dlib/pixel.h>
+#include <dlib/svm_threaded.h>
+#include <dlib/array.h>
+#include <dlib/set_utils.h>
+#include <dlib/array2d.h>
+#include <dlib/image_keypoint.h>
+#include <dlib/image_processing.h>
+#include <dlib/image_transforms.h>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.object_detector");
+
+// ----------------------------------------------------------------------------------------
+
+ struct funny_image
+ {
+ array2d<unsigned char> img;
+ long nr() const { return img.nr(); }
+ long nc() const { return img.nc(); }
+ };
+
+ void swap(funny_image& a, funny_image& b)
+ {
+ a.img.swap(b.img);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_array_type,
+ typename detector_type
+ >
+ void validate_some_object_detector_stuff (
+ const image_array_type& images,
+ detector_type& detector,
+ double eps = 1e-10
+ )
+ {
+ for (unsigned long i = 0; i < images.size(); ++i)
+ {
+ std::vector<rectangle> dets = detector(images[i]);
+ std::vector<std::pair<double,rectangle> > dets2;
+
+ detector(images[i], dets2);
+
+ matrix<double,0,1> psi(detector.get_w().size());
+ matrix<double,0,1> psi2(detector.get_w().size());
+ const double thresh = detector.get_w()(detector.get_w().size()-1);
+
+ DLIB_TEST(dets.size() == dets2.size());
+ for (unsigned long j = 0; j < dets.size(); ++j)
+ {
+ DLIB_TEST(dets[j] == dets2[j].second);
+
+ const full_object_detection fdet = detector.get_scanner().get_full_object_detection(dets[j], detector.get_w());
+ psi = 0;
+ detector.get_scanner().get_feature_vector(fdet, psi);
+
+ double check_score = dot(psi,detector.get_w()) - thresh;
+ DLIB_TEST_MSG(std::abs(check_score - dets2[j].first) < eps, std::abs(check_score - dets2[j].first) << " check_score: "<< check_score);
+ }
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class very_simple_feature_extractor : noncopyable
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object is a feature extractor which goes to every pixel in an image and
+ produces a 32 dimensional feature vector. This vector is an indicator vector
+ which records the pattern of pixel values in a 4-connected region. So it should
+ be able to distinguish basic things like whether or not a location falls on the
+ corner of a white box, on an edge, in the middle, etc.
+
+
+ Note that this object also implements the interface defined in dlib/image_keypoint/hashed_feature_image_abstract.h.
+ This means all the member functions in this object are supposed to behave as
+ described in the hashed_feature_image specification. So when you define your own
+ feature extractor objects you should probably refer yourself to that documentation
+ in addition to reading this example program.
+ !*/
+
+
+ public:
+
+ inline void load (
+ const funny_image& img_
+ )
+ {
+ const array2d<unsigned char>& img = img_.img;
+
+ feat_image.set_size(img.nr(), img.nc());
+ assign_all_pixels(feat_image,0);
+ for (long r = 1; r+1 < img.nr(); ++r)
+ {
+ for (long c = 1; c+1 < img.nc(); ++c)
+ {
+ unsigned char f = 0;
+ if (img[r][c]) f |= 0x1;
+ if (img[r][c+1]) f |= 0x2;
+ if (img[r][c-1]) f |= 0x4;
+ if (img[r+1][c]) f |= 0x8;
+ if (img[r-1][c]) f |= 0x10;
+
+ // Store the code value for the pattern of pixel values in the 4-connected
+ // neighborhood around this row and column.
+ feat_image[r][c] = f;
+ }
+ }
+ }
+
+ inline void load (
+ const array2d<unsigned char>& img
+ )
+ {
+ feat_image.set_size(img.nr(), img.nc());
+ assign_all_pixels(feat_image,0);
+ for (long r = 1; r+1 < img.nr(); ++r)
+ {
+ for (long c = 1; c+1 < img.nc(); ++c)
+ {
+ unsigned char f = 0;
+ if (img[r][c]) f |= 0x1;
+ if (img[r][c+1]) f |= 0x2;
+ if (img[r][c-1]) f |= 0x4;
+ if (img[r+1][c]) f |= 0x8;
+ if (img[r-1][c]) f |= 0x10;
+
+ // Store the code value for the pattern of pixel values in the 4-connected
+ // neighborhood around this row and column.
+ feat_image[r][c] = f;
+ }
+ }
+ }
+
+ inline size_t size () const { return feat_image.size(); }
+ inline long nr () const { return feat_image.nr(); }
+ inline long nc () const { return feat_image.nc(); }
+
+ inline long get_num_dimensions (
+ ) const
+ {
+ // Return the dimensionality of the vectors produced by operator()
+ return 32;
+ }
+
+ typedef std::vector<std::pair<unsigned int,double> > descriptor_type;
+
+ inline const descriptor_type& operator() (
+ long row,
+ long col
+ ) const
+ /*!
+ requires
+ - 0 <= row < nr()
+ - 0 <= col < nc()
+ ensures
+ - returns a sparse vector which describes the image at the given row and column.
+ In particular, this is a vector that is 0 everywhere except for one element.
+ !*/
+ {
+ feat.clear();
+ const unsigned long only_nonzero_element_index = feat_image[row][col];
+ feat.push_back(make_pair(only_nonzero_element_index,1.0));
+ return feat;
+ }
+
+ // This block of functions is meant to provide a way to map between the row/col space taken by
+ // this object's operator() function and the images supplied to load(). In this example it's trivial.
+ // However, in general, you might create feature extractors which don't perform extraction at every
+ // possible image location (e.g. the hog_image) and thus result in some more complex mapping.
+ inline const rectangle get_block_rect ( long row, long col) const { return centered_rect(col,row,3,3); }
+ inline const point image_to_feat_space ( const point& p) const { return p; }
+ inline const rectangle image_to_feat_space ( const rectangle& rect) const { return rect; }
+ inline const point feat_to_image_space ( const point& p) const { return p; }
+ inline const rectangle feat_to_image_space ( const rectangle& rect) const { return rect; }
+
+ inline friend void serialize ( const very_simple_feature_extractor& item, std::ostream& out) { serialize(item.feat_image, out); }
+ inline friend void deserialize ( very_simple_feature_extractor& item, std::istream& in ) { deserialize(item.feat_image, in); }
+
+ void copy_configuration ( const very_simple_feature_extractor& ){}
+
+ private:
+ array2d<unsigned char> feat_image;
+
+ // This variable doesn't logically contribute to the state of this object. It is here
+ // only to avoid returning a descriptor_type object by value inside the operator() method.
+ mutable descriptor_type feat;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_array_type
+ >
+ void make_simple_test_data (
+ image_array_type& images,
+ std::vector<std::vector<rectangle> >& object_locations
+ )
+ {
+ images.clear();
+ object_locations.clear();
+
+ images.resize(3);
+ images[0].set_size(400,400);
+ images[1].set_size(400,400);
+ images[2].set_size(400,400);
+
+ // set all the pixel values to black
+ assign_all_pixels(images[0], 0);
+ assign_all_pixels(images[1], 0);
+ assign_all_pixels(images[2], 0);
+
+ // Now make some squares and draw them onto our black images. All the
+ // squares will be 70 pixels wide and tall.
+
+ std::vector<rectangle> temp;
+ temp.push_back(centered_rect(point(100,100), 70,70));
+ fill_rect(images[0],temp.back(),255); // Paint the square white
+ temp.push_back(centered_rect(point(200,300), 70,70));
+ fill_rect(images[0],temp.back(),255); // Paint the square white
+ object_locations.push_back(temp);
+
+ temp.clear();
+ temp.push_back(centered_rect(point(140,200), 70,70));
+ fill_rect(images[1],temp.back(),255); // Paint the square white
+ temp.push_back(centered_rect(point(303,200), 70,70));
+ fill_rect(images[1],temp.back(),255); // Paint the square white
+ object_locations.push_back(temp);
+
+ temp.clear();
+ temp.push_back(centered_rect(point(123,121), 70,70));
+ fill_rect(images[2],temp.back(),255); // Paint the square white
+ object_locations.push_back(temp);
+
+ // corrupt each image with random noise just to make this a little more
+ // challenging
+ dlib::rand rnd;
+ for (unsigned long i = 0; i < images.size(); ++i)
+ {
+ for (long r = 0; r < images[i].nr(); ++r)
+ {
+ for (long c = 0; c < images[i].nc(); ++c)
+ {
+ typedef typename image_array_type::type image_type;
+ typedef typename image_type::type type;
+ images[i][r][c] = (type)put_in_range(0,255,images[i][r][c] + 10*rnd.get_random_gaussian());
+ }
+ }
+ }
+ }
+
+ template <
+ typename image_array_type
+ >
+ void make_simple_test_data (
+ image_array_type& images,
+ std::vector<std::vector<full_object_detection> >& object_locations
+ )
+ {
+ images.clear();
+ object_locations.clear();
+
+
+ images.resize(3);
+ images[0].set_size(400,400);
+ images[1].set_size(400,400);
+ images[2].set_size(400,400);
+
+ // set all the pixel values to black
+ assign_all_pixels(images[0], 0);
+ assign_all_pixels(images[1], 0);
+ assign_all_pixels(images[2], 0);
+
+ // Now make some squares and draw them onto our black images. All the
+ // squares will be 70 pixels wide and tall.
+ const int shrink = 0;
+ std::vector<full_object_detection> temp;
+
+ rectangle rect = centered_rect(point(100,100), 70,71);
+ std::vector<point> movable_parts;
+ movable_parts.push_back(shrink_rect(rect,shrink).tl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).tr_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).bl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).br_corner());
+ temp.push_back(full_object_detection(rect, movable_parts));
+ fill_rect(images[0],rect,255); // Paint the square white
+
+ rect = centered_rect(point(200,200), 70,71);
+ movable_parts.clear();
+ movable_parts.push_back(shrink_rect(rect,shrink).tl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).tr_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).bl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).br_corner());
+ temp.push_back(full_object_detection(rect, movable_parts));
+ fill_rect(images[0],rect,255); // Paint the square white
+
+ object_locations.push_back(temp);
+ // ------------------------------------
+ temp.clear();
+
+ rect = centered_rect(point(140,200), 70,71);
+ movable_parts.clear();
+ movable_parts.push_back(shrink_rect(rect,shrink).tl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).tr_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).bl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).br_corner());
+ temp.push_back(full_object_detection(rect, movable_parts));
+ fill_rect(images[1],rect,255); // Paint the square white
+
+
+ rect = centered_rect(point(303,200), 70,71);
+ movable_parts.clear();
+ movable_parts.push_back(shrink_rect(rect,shrink).tl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).tr_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).bl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).br_corner());
+ temp.push_back(full_object_detection(rect, movable_parts));
+ fill_rect(images[1],rect,255); // Paint the square white
+
+ object_locations.push_back(temp);
+ // ------------------------------------
+ temp.clear();
+
+ rect = centered_rect(point(123,121), 70,71);
+ movable_parts.clear();
+ movable_parts.push_back(shrink_rect(rect,shrink).tl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).tr_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).bl_corner());
+ movable_parts.push_back(shrink_rect(rect,shrink).br_corner());
+ temp.push_back(full_object_detection(rect, movable_parts));
+ fill_rect(images[2],rect,255); // Paint the square white
+
+ object_locations.push_back(temp);
+
+ // corrupt each image with random noise just to make this a little more
+ // challenging
+ dlib::rand rnd;
+ for (unsigned long i = 0; i < images.size(); ++i)
+ {
+ for (long r = 0; r < images[i].nr(); ++r)
+ {
+ for (long c = 0; c < images[i].nc(); ++c)
+ {
+ typedef typename image_array_type::type image_type;
+ typedef typename image_type::type type;
+ images[i][r][c] = (type)put_in_range(0,255,images[i][r][c] + 40*rnd.get_random_gaussian());
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_fhog_pyramid (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_fhog_pyramid()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef scan_fhog_pyramid<pyramid_down<2> > image_scanner_type;
+ image_scanner_type scanner;
+ scanner.set_detection_window_size(35,35);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ trainer.set_overlap_tester(test_box_overlap(0,0));
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector, 1e-6);
+ }
+
+ {
+ std::vector<object_detector<image_scanner_type> > detectors;
+ detectors.push_back(detector);
+ detectors.push_back(detector);
+ detectors.push_back(detector);
+
+ std::vector<rectangle> dets1 = evaluate_detectors(detectors, images[0]);
+ std::vector<rectangle> dets2 = detector(images[0]);
+ DLIB_TEST(dets1.size() > 0);
+ DLIB_TEST(dets2.size()*3 == dets1.size());
+ dlib::set<rectangle>::kernel_1a_c d1, d2;
+ for (unsigned long i = 0; i < dets1.size(); ++i)
+ {
+ if (!d1.is_member(dets1[i]))
+ d1.add(dets1[i]);
+ }
+ for (unsigned long i = 0; i < dets2.size(); ++i)
+ {
+ if (!d2.is_member(dets2[i]))
+ d2.add(dets2[i]);
+ }
+ DLIB_TEST(d1.size() == d2.size());
+ DLIB_TEST(set_intersection_size(d1,d2) == d1.size());
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_1 (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_1()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef hashed_feature_image<hog_image<3,3,1,4,hog_signed_gradient,hog_full_interpolation> > feature_extractor_type;
+ typedef scan_image_pyramid<pyramid_down<2>, feature_extractor_type> image_scanner_type;
+ image_scanner_type scanner;
+ const rectangle object_box = compute_box_dimensions(1,35*35);
+ scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2));
+ setup_hashed_features(scanner, images, 9);
+ use_uniform_feature_weights(scanner);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ trainer.set_overlap_tester(test_box_overlap(0,0));
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_1_boxes (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_1_boxes()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef hashed_feature_image<hog_image<3,3,1,4,hog_signed_gradient,hog_full_interpolation> > feature_extractor_type;
+ typedef scan_image_boxes<feature_extractor_type> image_scanner_type;
+ image_scanner_type scanner;
+ setup_hashed_features(scanner, images, 9);
+ use_uniform_feature_weights(scanner);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ trainer.set_overlap_tester(test_box_overlap(0,0));
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_1m (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_1m()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<full_object_detection> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef hashed_feature_image<hog_image<3,3,1,4,hog_signed_gradient,hog_full_interpolation> > feature_extractor_type;
+ typedef scan_image_pyramid<pyramid_down<2>, feature_extractor_type> image_scanner_type;
+ image_scanner_type scanner;
+ const rectangle object_box = compute_box_dimensions(1,35*35);
+ std::vector<rectangle> mboxes;
+ const int mbox_size = 20;
+ mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size));
+ mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size));
+ mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size));
+ mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size));
+ scanner.add_detection_template(object_box, create_grid_detection_template(object_box,1,1), mboxes);
+ setup_hashed_features(scanner, images, 9);
+ use_uniform_feature_weights(scanner);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ trainer.set_overlap_tester(test_box_overlap(0,0));
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_1_fine_hog (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_1_fine_hog()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef hashed_feature_image<fine_hog_image<3,3,2,4,hog_signed_gradient> > feature_extractor_type;
+ typedef scan_image_pyramid<pyramid_down<2>, feature_extractor_type> image_scanner_type;
+ image_scanner_type scanner;
+ const rectangle object_box = compute_box_dimensions(1,35*35);
+ scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2));
+ setup_hashed_features(scanner, images, 9);
+ use_uniform_feature_weights(scanner);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ trainer.set_overlap_tester(test_box_overlap(0,0));
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_1_poly (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_1_poly()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef hashed_feature_image<poly_image<2> > feature_extractor_type;
+ typedef scan_image_pyramid<pyramid_down<2>, feature_extractor_type> image_scanner_type;
+ image_scanner_type scanner;
+ const rectangle object_box = compute_box_dimensions(1,35*35);
+ scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2));
+ setup_hashed_features(scanner, images, 9);
+ use_uniform_feature_weights(scanner);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ trainer.set_overlap_tester(test_box_overlap(0,0));
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_1m_poly (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_1_poly()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<full_object_detection> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef hashed_feature_image<poly_image<2> > feature_extractor_type;
+ typedef scan_image_pyramid<pyramid_down<3>, feature_extractor_type> image_scanner_type;
+ image_scanner_type scanner;
+ const rectangle object_box = compute_box_dimensions(1,35*35);
+ std::vector<rectangle> mboxes;
+ const int mbox_size = 20;
+ mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size));
+ mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size));
+ mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size));
+ mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size));
+ scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2), mboxes);
+ setup_hashed_features(scanner, images, 9);
+ use_uniform_feature_weights(scanner);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ trainer.set_overlap_tester(test_box_overlap(0,0));
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_1_poly_nn (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_1_poly_nn()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef nearest_neighbor_feature_image<poly_image<5> > feature_extractor_type;
+ typedef scan_image_pyramid<pyramid_down<2>, feature_extractor_type> image_scanner_type;
+ image_scanner_type scanner;
+
+ setup_grid_detection_templates(scanner, object_locations, 2, 2);
+ feature_extractor_type nnfe;
+ pyramid_down<2> pyr_down;
+ poly_image<5> polyi;
+ nnfe.set_basis(randomly_sample_image_features(images, pyr_down, polyi, 80));
+ scanner.copy_configuration(nnfe);
+
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_1_poly_nn_boxes (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_1_poly_nn_boxes()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef nearest_neighbor_feature_image<poly_image<5> > feature_extractor_type;
+ typedef scan_image_boxes<feature_extractor_type> image_scanner_type;
+ image_scanner_type scanner;
+
+ feature_extractor_type nnfe;
+ pyramid_down<2> pyr_down;
+ poly_image<5> polyi;
+ nnfe.set_basis(randomly_sample_image_features(images, pyr_down, polyi, 80));
+ scanner.copy_configuration(nnfe);
+
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_2 (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_2()";
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ grayscale_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images, object_locations);
+
+ typedef scan_image_pyramid<pyramid_down<5>, very_simple_feature_extractor> image_scanner_type;
+ image_scanner_type scanner;
+ const rectangle object_box = compute_box_dimensions(1,70*70);
+ scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2));
+ scanner.set_max_pyramid_levels(1);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(0);
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ res = cross_validate_object_detection_trainer(trainer, images, object_locations, 3);
+ dlog << LINFO << "3-fold cross validation (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+ validate_some_object_detector_stuff(images, detector);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class pyramid_down_funny : noncopyable
+ {
+ pyramid_down<2> pyr;
+ public:
+
+ template <typename T>
+ dlib::vector<double,2> point_down ( const dlib::vector<T,2>& p) const { return pyr.point_down(p); }
+
+ template <typename T>
+ dlib::vector<double,2> point_up ( const dlib::vector<T,2>& p) const { return pyr.point_up(p); }
+
+ template <typename T>
+ dlib::vector<double,2> point_down ( const dlib::vector<T,2>& p, unsigned int levels) const { return pyr.point_down(p,levels); }
+
+ template <typename T>
+ dlib::vector<double,2> point_up ( const dlib::vector<T,2>& p, unsigned int levels) const { return pyr.point_up(p,levels); }
+
+ rectangle rect_up ( const rectangle& rect) const { return pyr.rect_up(rect); }
+
+ rectangle rect_up ( const rectangle& rect, unsigned int levels) const { return pyr.rect_up(rect,levels); }
+
+ rectangle rect_down ( const rectangle& rect) const { return pyr.rect_down(rect); }
+
+ rectangle rect_down ( const rectangle& rect, unsigned int levels) const { return pyr.rect_down(rect,levels); }
+
+ template <
+ typename in_image_type,
+ typename out_image_type
+ >
+ void operator() (
+ const in_image_type& original,
+ out_image_type& down
+ ) const
+ {
+ pyr(original.img, down.img);
+ }
+
+ };
+
+ // make sure everything works even when the image isn't a dlib::array2d.
+ // So test with funny_image.
+ void test_3 (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_3()";
+
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ typedef dlib::array<funny_image> funny_image_array_type;
+ grayscale_image_array_type images_temp;
+ funny_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images_temp, object_locations);
+ images.resize(images_temp.size());
+ for (unsigned long i = 0; i < images_temp.size(); ++i)
+ {
+ images[i].img.swap(images_temp[i]);
+ }
+
+ typedef scan_image_pyramid<pyramid_down_funny, very_simple_feature_extractor> image_scanner_type;
+ image_scanner_type scanner;
+ const rectangle object_box = compute_box_dimensions(1,70*70);
+ scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2));
+ scanner.set_max_pyramid_levels(1);
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ res = cross_validate_object_detection_trainer(trainer, images, object_locations, 3);
+ dlog << LINFO << "3-fold cross validation (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class funny_box_generator
+ {
+ public:
+ template <typename image_type>
+ void operator() (
+ const image_type& img,
+ std::vector<rectangle>& rects
+ ) const
+ {
+ rects.clear();
+ find_candidate_object_locations(img.img, rects);
+ dlog << LINFO << "funny_box_generator, rects.size(): "<< rects.size();
+ }
+ };
+
+ inline void serialize(const funny_box_generator&, std::ostream& ) {}
+ inline void deserialize(funny_box_generator&, std::istream& ) {}
+
+
+ // make sure everything works even when the image isn't a dlib::array2d.
+ // So test with funny_image.
+ void test_3_boxes (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test_3_boxes()";
+
+
+ typedef dlib::array<array2d<unsigned char> > grayscale_image_array_type;
+ typedef dlib::array<funny_image> funny_image_array_type;
+ grayscale_image_array_type images_temp;
+ funny_image_array_type images;
+ std::vector<std::vector<rectangle> > object_locations;
+ make_simple_test_data(images_temp, object_locations);
+ images.resize(images_temp.size());
+ for (unsigned long i = 0; i < images_temp.size(); ++i)
+ {
+ images[i].img.swap(images_temp[i]);
+ }
+
+ typedef scan_image_boxes<very_simple_feature_extractor, funny_box_generator> image_scanner_type;
+ image_scanner_type scanner;
+ structural_object_detection_trainer<image_scanner_type> trainer(scanner);
+ trainer.set_num_threads(4);
+ object_detector<image_scanner_type> detector = trainer.train(images, object_locations);
+
+ matrix<double> res = test_object_detection_function(detector, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ res = cross_validate_object_detection_trainer(trainer, images, object_locations, 3);
+ dlog << LINFO << "3-fold cross validation (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+
+ {
+ ostringstream sout;
+ serialize(detector, sout);
+ istringstream sin(sout.str());
+ object_detector<image_scanner_type> d2;
+ deserialize(d2, sin);
+ matrix<double> res = test_object_detection_function(d2, images, object_locations);
+ dlog << LINFO << "Test detector (precision,recall): " << res;
+ DLIB_TEST(sum(res) == 3);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class object_detector_tester : public tester
+ {
+ public:
+ object_detector_tester (
+ ) :
+ tester ("test_object_detector",
+ "Runs tests on the structural object detection stuff.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_fhog_pyramid();
+ test_1_boxes();
+ test_1_poly_nn_boxes();
+ test_3_boxes();
+
+ test_1();
+ test_1m();
+ test_1_fine_hog();
+ test_1_poly();
+ test_1m_poly();
+ test_1_poly_nn();
+ test_2();
+ test_3();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/oca.cpp b/ml/dlib/dlib/test/oca.cpp
new file mode 100644
index 000000000..97881a758
--- /dev/null
+++ b/ml/dlib/dlib/test/oca.cpp
@@ -0,0 +1,244 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/optimization.h>
+#include <dlib/svm.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.oca");
+
+// ----------------------------------------------------------------------------------------
+
+ class test_oca : public tester
+ {
+
+ public:
+ test_oca (
+ ) :
+ tester ("test_oca",
+ "Runs tests on the oca component.")
+ {
+ }
+
+ void perform_test(
+ )
+ {
+ print_spinner();
+
+ typedef matrix<double,0,1> w_type;
+ w_type w;
+
+ decision_function<linear_kernel<w_type> > df;
+ svm_c_linear_trainer<linear_kernel<w_type> > trainer;
+ trainer.set_c_class1(2);
+ trainer.set_c_class1(3);
+ trainer.set_learns_nonnegative_weights(true);
+ trainer.set_epsilon(1e-12);
+
+ std::vector<w_type> x;
+ w_type temp(2);
+ temp = -1, 1;
+ x.push_back(temp);
+ temp = 1, -1;
+ x.push_back(temp);
+
+ std::vector<double> y;
+ y.push_back(+1);
+ y.push_back(-1);
+
+ w_type true_w(3);
+
+ oca solver;
+
+ // test the version without a non-negativity constraint on w.
+ solver(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 0);
+ dlog << LINFO << trans(w);
+ true_w = -0.5, 0.5, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ solver.solve_with_elastic_net(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 0.5);
+ dlog << LINFO << trans(w);
+ true_w = -0.5, 0.5, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ print_spinner();
+
+ w_type prior = true_w;
+ solver(make_oca_problem_c_svm<w_type>(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior);
+ dlog << LINFO << trans(w);
+ true_w = -0.5, 0.5, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ prior = 0,0,0;
+ solver(make_oca_problem_c_svm<w_type>(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior);
+ dlog << LINFO << trans(w);
+ true_w = -0.5, 0.5, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ prior = -1,1,0;
+ solver(make_oca_problem_c_svm<w_type>(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior);
+ dlog << LINFO << trans(w);
+ true_w = -1.0, 1.0, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ prior = -0.2,0.2,0;
+ solver(make_oca_problem_c_svm<w_type>(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior);
+ dlog << LINFO << trans(w);
+ true_w = -0.5, 0.5, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ prior = -10.2,-1,0;
+ solver(make_oca_problem_c_svm<w_type>(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior);
+ dlog << LINFO << trans(w);
+ true_w = -10.2, -1.0, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ print_spinner();
+
+ // test the version with a non-negativity constraint on w.
+ solver(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 9999);
+ dlog << LINFO << trans(w);
+ true_w = 0, 1, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ df = trainer.train(x,y);
+ w = join_cols(df.basis_vectors(0), uniform_matrix<double>(1,1,-df.b));
+ true_w = 0, 1, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST_MSG(max(abs(w-true_w)) < 1e-9, max(abs(w-true_w)));
+
+
+ print_spinner();
+
+ // test the version with a non-negativity constraint on w.
+ solver(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 2);
+ dlog << LINFO << trans(w);
+ true_w = 0, 1, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ print_spinner();
+
+
+ // test the version with a non-negativity constraint on w.
+ solver(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 1);
+ dlog << LINFO << trans(w);
+ true_w = 0, 1, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ print_spinner();
+
+
+ // switching the labels should change which w weight goes negative.
+ y.clear();
+ y.push_back(-1);
+ y.push_back(+1);
+
+
+ solver(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 0);
+ dlog << LINFO << trans(w);
+ true_w = 0.5, -0.5, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ print_spinner();
+
+ solver(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 1);
+ dlog << LINFO << trans(w);
+ true_w = 0.5, -0.5, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ print_spinner();
+
+ solver(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 2);
+ dlog << LINFO << trans(w);
+ true_w = 1, 0, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ print_spinner();
+
+ solver(make_oca_problem_c_svm<w_type>(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 5);
+ dlog << LINFO << trans(w);
+ true_w = 1, 0, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ df = trainer.train(x,y);
+ w = join_cols(df.basis_vectors(0), uniform_matrix<double>(1,1,-df.b));
+ true_w = 1, 0, 0;
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST_MSG(max(abs(w-true_w)) < 1e-9, max(abs(w-true_w)));
+
+
+
+ x.clear();
+ y.clear();
+ temp = -2, 2;
+ x.push_back(temp);
+ temp = 0, -0;
+ x.push_back(temp);
+
+ y.push_back(+1);
+ y.push_back(-1);
+
+ trainer.set_c(10);
+ df = trainer.train(x,y);
+ w = join_cols(df.basis_vectors(0), uniform_matrix<double>(1,1,-df.b));
+ true_w = 0, 1, -1;
+ dlog << LINFO << "w: " << trans(w);
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+
+ x.clear();
+ y.clear();
+ temp = -2, 2;
+ x.push_back(temp);
+ temp = 0, -0;
+ x.push_back(temp);
+
+ y.push_back(-1);
+ y.push_back(+1);
+
+ trainer.set_c(10);
+ df = trainer.train(x,y);
+ w = join_cols(df.basis_vectors(0), uniform_matrix<double>(1,1,-df.b));
+ true_w = 1, 0, 1;
+ dlog << LINFO << "w: " << trans(w);
+ dlog << LINFO << "error: "<< max(abs(w-true_w));
+ DLIB_TEST(max(abs(w-true_w)) < 1e-10);
+
+ }
+
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/one_vs_all_trainer.cpp b/ml/dlib/dlib/test/one_vs_all_trainer.cpp
new file mode 100644
index 000000000..b928714b2
--- /dev/null
+++ b/ml/dlib/dlib/test/one_vs_all_trainer.cpp
@@ -0,0 +1,305 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+#include <vector>
+#include <sstream>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.one_vs_all_trainer");
+
+
+ class test_one_vs_all_trainer : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ test_one_vs_all_trainer (
+ ) :
+ tester (
+ "test_one_vs_all_trainer", // the command line argument name for this test
+ "Run tests on the one_vs_all_trainer stuff.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+
+
+ template <typename sample_type, typename label_type>
+ void generate_data (
+ std::vector<sample_type>& samples,
+ std::vector<label_type>& labels
+ )
+ {
+ const long num = 50;
+
+ sample_type m;
+
+ dlib::rand rnd;
+
+
+ // make some samples near the origin
+ double radius = 0.5;
+ for (long i = 0; i < num+10; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ labels.push_back(1);
+ }
+
+ // make some samples in a circle around the origin but far away
+ radius = 10.0;
+ for (long i = 0; i < num+20; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ labels.push_back(2);
+ }
+
+ // make some samples in a circle around the point (25,25)
+ radius = 4.0;
+ for (long i = 0; i < num+30; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // translate this point away from the origin
+ m(0) += 25;
+ m(1) += 25;
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ labels.push_back(3);
+ }
+ }
+
+ template <typename label_type, typename scalar_type>
+ void run_test (
+ )
+ {
+ print_spinner();
+ typedef matrix<scalar_type,2,1> sample_type;
+
+ std::vector<sample_type> samples, norm_samples;
+ std::vector<label_type> labels;
+
+ // First, get our labeled set of training data
+ generate_data(samples, labels);
+
+ typedef one_vs_all_trainer<any_trainer<sample_type,scalar_type>,label_type > ova_trainer;
+
+
+ ova_trainer trainer;
+
+ typedef polynomial_kernel<sample_type> poly_kernel;
+ typedef radial_basis_kernel<sample_type> rbf_kernel;
+
+ // make the binary trainers and set some parameters
+ krr_trainer<rbf_kernel> rbf_trainer;
+ svm_nu_trainer<poly_kernel> poly_trainer;
+ poly_trainer.set_kernel(poly_kernel(0.1, 1, 2));
+ rbf_trainer.set_kernel(rbf_kernel(0.1));
+
+
+ trainer.set_trainer(rbf_trainer);
+ trainer.set_trainer(poly_trainer, 1);
+
+ randomize_samples(samples, labels);
+ matrix<double> res = cross_validate_multiclass_trainer(trainer, samples, labels, 2);
+
+ print_spinner();
+
+ matrix<scalar_type> ans(3,3);
+ ans = 60, 0, 0,
+ 0, 70, 0,
+ 0, 0, 80;
+
+ DLIB_TEST_MSG(ans == res, "res: \n" << res);
+
+ // test using a normalized_function with a one_vs_all_decision_function
+ {
+ poly_trainer.set_kernel(poly_kernel(1.1, 1, 2));
+ trainer.set_trainer(poly_trainer, 1);
+ vector_normalizer<sample_type> normalizer;
+ normalizer.train(samples);
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ norm_samples.push_back(normalizer(samples[i]));
+ normalized_function<one_vs_all_decision_function<ova_trainer> > ndf;
+ ndf.function = trainer.train(norm_samples, labels);
+ ndf.normalizer = normalizer;
+ DLIB_TEST(ndf(samples[0]) == labels[0]);
+ DLIB_TEST(ndf(samples[40]) == labels[40]);
+ DLIB_TEST(ndf(samples[90]) == labels[90]);
+ DLIB_TEST(ndf(samples[120]) == labels[120]);
+ poly_trainer.set_kernel(poly_kernel(0.1, 1, 2));
+ trainer.set_trainer(poly_trainer, 1);
+ print_spinner();
+ }
+
+ one_vs_all_decision_function<ova_trainer> df = trainer.train(samples, labels);
+
+ DLIB_TEST(df.number_of_classes() == 3);
+
+ DLIB_TEST(df(samples[0]) == labels[0]);
+ DLIB_TEST(df(samples[90]) == labels[90]);
+
+
+ one_vs_all_decision_function<ova_trainer,
+ decision_function<poly_kernel>, // This is the output of the poly_trainer
+ decision_function<rbf_kernel> // This is the output of the rbf_trainer
+ > df2, df3;
+
+
+ df2 = df;
+ ofstream fout("df.dat", ios::binary);
+ serialize(df2, fout);
+ fout.close();
+
+ // load the function back in from disk and store it in df3.
+ ifstream fin("df.dat", ios::binary);
+ deserialize(df3, fin);
+
+
+ DLIB_TEST(df3(samples[0]) == labels[0]);
+ DLIB_TEST(df3(samples[90]) == labels[90]);
+ res = test_multiclass_decision_function(df3, samples, labels);
+
+ DLIB_TEST(res == ans);
+
+
+ }
+
+ template <typename label_type, typename scalar_type>
+ void run_probabilistic_test (
+ )
+ {
+ print_spinner();
+ typedef matrix<scalar_type,2,1> sample_type;
+
+ std::vector<sample_type> samples;
+ std::vector<label_type> labels;
+
+ // First, get our labeled set of training data
+ generate_data(samples, labels);
+
+ typedef one_vs_all_trainer<any_trainer<sample_type,scalar_type>,label_type > ova_trainer;
+
+
+ ova_trainer trainer;
+
+ typedef polynomial_kernel<sample_type> poly_kernel;
+ typedef radial_basis_kernel<sample_type> rbf_kernel;
+
+ // make the binary trainers and set some parameters
+ krr_trainer<rbf_kernel> rbf_trainer;
+ svm_nu_trainer<poly_kernel> poly_trainer;
+ poly_trainer.set_kernel(poly_kernel(0.1, 1, 2));
+ rbf_trainer.set_kernel(rbf_kernel(0.1));
+
+
+ trainer.set_trainer(probabilistic(rbf_trainer, 3));
+ trainer.set_trainer(probabilistic(poly_trainer, 3), 1);
+
+ randomize_samples(samples, labels);
+ matrix<double> res = cross_validate_multiclass_trainer(trainer, samples, labels, 2);
+
+ print_spinner();
+
+ matrix<scalar_type> ans(3,3);
+ ans = 60, 0, 0,
+ 0, 70, 0,
+ 0, 0, 80;
+
+ DLIB_TEST_MSG(ans == res, "res: \n" << res);
+
+ one_vs_all_decision_function<ova_trainer> df = trainer.train(samples, labels);
+
+ DLIB_TEST(df.number_of_classes() == 3);
+
+ DLIB_TEST(df(samples[0]) == labels[0]);
+ DLIB_TEST(df(samples[90]) == labels[90]);
+
+
+ one_vs_all_decision_function<ova_trainer,
+ probabilistic_function<decision_function<poly_kernel> >, // This is the output of the poly_trainer
+ probabilistic_function<decision_function<rbf_kernel> > // This is the output of the rbf_trainer
+ > df2, df3;
+
+
+ df2 = df;
+ ofstream fout("df.dat", ios::binary);
+ serialize(df2, fout);
+ fout.close();
+
+ // load the function back in from disk and store it in df3.
+ ifstream fin("df.dat", ios::binary);
+ deserialize(df3, fin);
+
+
+ DLIB_TEST(df3(samples[0]) == labels[0]);
+ DLIB_TEST(df3(samples[90]) == labels[90]);
+ res = test_multiclass_decision_function(df3, samples, labels);
+
+ DLIB_TEST(res == ans);
+
+
+ }
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "run_test<double,double>()";
+ run_test<double,double>();
+
+ dlog << LINFO << "run_test<int,double>()";
+ run_test<int,double>();
+
+ dlog << LINFO << "run_test<double,float>()";
+ run_test<double,float>();
+
+ dlog << LINFO << "run_test<int,float>()";
+ run_test<int,float>();
+
+ dlog << LINFO << "run_probabilistic_test<double,double>()";
+ run_probabilistic_test<double,double>();
+
+ dlog << LINFO << "run_probabilistic_test<int,double>()";
+ run_probabilistic_test<int,double>();
+
+ dlog << LINFO << "run_probabilistic_test<double,float>()";
+ run_probabilistic_test<double,float>();
+
+ dlog << LINFO << "run_probabilistic_test<int,float>()";
+ run_probabilistic_test<int,float>();
+ }
+ };
+
+ test_one_vs_all_trainer a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/one_vs_one_trainer.cpp b/ml/dlib/dlib/test/one_vs_one_trainer.cpp
new file mode 100644
index 000000000..70cdefaf9
--- /dev/null
+++ b/ml/dlib/dlib/test/one_vs_one_trainer.cpp
@@ -0,0 +1,218 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+#include <dlib/statistics.h>
+#include <vector>
+#include <sstream>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.one_vs_one_trainer");
+
+
+ class test_one_vs_one_trainer : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ test_one_vs_one_trainer (
+ ) :
+ tester (
+ "test_one_vs_one_trainer", // the command line argument name for this test
+ "Run tests on the one_vs_one_trainer stuff.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+
+
+ template <typename sample_type, typename label_type>
+ void generate_data (
+ std::vector<sample_type>& samples,
+ std::vector<label_type>& labels
+ )
+ {
+ const long num = 50;
+
+ sample_type m;
+
+ dlib::rand rnd;
+
+
+ // make some samples near the origin
+ double radius = 0.5;
+ for (long i = 0; i < num+10; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ labels.push_back(1);
+ }
+
+ // make some samples in a circle around the origin but far away
+ radius = 10.0;
+ for (long i = 0; i < num+20; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ labels.push_back(2);
+ }
+
+ // make some samples in a circle around the point (25,25)
+ radius = 4.0;
+ for (long i = 0; i < num+30; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // translate this point away from the origin
+ m(0) += 25;
+ m(1) += 25;
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ labels.push_back(3);
+ }
+ }
+
+ template <typename label_type, typename scalar_type>
+ void run_test (
+ )
+ {
+ print_spinner();
+ typedef matrix<scalar_type,2,1> sample_type;
+
+ std::vector<sample_type> samples, norm_samples;
+ std::vector<label_type> labels;
+
+ // First, get our labeled set of training data
+ generate_data(samples, labels);
+
+ typedef one_vs_one_trainer<any_trainer<sample_type,scalar_type>,label_type > ovo_trainer;
+
+
+ ovo_trainer trainer;
+
+ typedef histogram_intersection_kernel<sample_type> hist_kernel;
+ typedef radial_basis_kernel<sample_type> rbf_kernel;
+
+ // make the binary trainers and set some parameters
+ krr_trainer<rbf_kernel> rbf_trainer;
+ svm_nu_trainer<hist_kernel> hist_trainer;
+ rbf_trainer.set_kernel(rbf_kernel(0.1));
+
+
+ trainer.set_trainer(rbf_trainer);
+ trainer.set_trainer(hist_trainer, 1, 2);
+
+ randomize_samples(samples, labels);
+ matrix<double> res = cross_validate_multiclass_trainer(trainer, samples, labels, 2);
+
+ print_spinner();
+
+ matrix<scalar_type> ans(3,3);
+ ans = 60, 0, 0,
+ 0, 70, 0,
+ 0, 0, 80;
+
+ DLIB_TEST_MSG(ans == res, "res: \n" << res);
+
+ // test using a normalized_function with a one_vs_one_decision_function
+ {
+ trainer.set_trainer(hist_trainer, 1, 2);
+ vector_normalizer<sample_type> normalizer;
+ normalizer.train(samples);
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ norm_samples.push_back(normalizer(samples[i]));
+ normalized_function<one_vs_one_decision_function<ovo_trainer> > ndf;
+ ndf.function = trainer.train(norm_samples, labels);
+ ndf.normalizer = normalizer;
+ DLIB_TEST(ndf(samples[0]) == labels[0]);
+ DLIB_TEST(ndf(samples[40]) == labels[40]);
+ DLIB_TEST(ndf(samples[90]) == labels[90]);
+ DLIB_TEST(ndf(samples[120]) == labels[120]);
+ trainer.set_trainer(hist_trainer, 1, 2);
+ print_spinner();
+ }
+
+
+
+
+ one_vs_one_decision_function<ovo_trainer> df = trainer.train(samples, labels);
+
+ DLIB_TEST(df.number_of_classes() == 3);
+
+ DLIB_TEST(df(samples[0]) == labels[0]);
+ DLIB_TEST(df(samples[90]) == labels[90]);
+
+
+ one_vs_one_decision_function<ovo_trainer,
+ decision_function<hist_kernel>, // This is the output of the hist_trainer
+ decision_function<rbf_kernel> // This is the output of the rbf_trainer
+ > df2, df3;
+
+
+ df2 = df;
+ ofstream fout("df.dat", ios::binary);
+ serialize(df2, fout);
+ fout.close();
+
+ // load the function back in from disk and store it in df3.
+ ifstream fin("df.dat", ios::binary);
+ deserialize(df3, fin);
+
+
+ DLIB_TEST(df3(samples[0]) == labels[0]);
+ DLIB_TEST(df3(samples[90]) == labels[90]);
+ res = test_multiclass_decision_function(df3, samples, labels);
+
+ DLIB_TEST(res == ans);
+
+
+ }
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "run_test<double,double>()";
+ run_test<double,double>();
+
+ dlog << LINFO << "run_test<int,double>()";
+ run_test<int,double>();
+
+ dlog << LINFO << "run_test<double,float>()";
+ run_test<double,float>();
+
+ dlog << LINFO << "run_test<int,float>()";
+ run_test<int,float>();
+ }
+ };
+
+ test_one_vs_one_trainer a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/opt_qp_solver.cpp b/ml/dlib/dlib/test/opt_qp_solver.cpp
new file mode 100644
index 000000000..ffa386323
--- /dev/null
+++ b/ml/dlib/dlib/test/opt_qp_solver.cpp
@@ -0,0 +1,813 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/optimization.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include <dlib/rand.h>
+#include <dlib/string.h>
+#include <dlib/statistics.h>
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.opt_qp_solver");
+
+// ----------------------------------------------------------------------------------------
+
+ class test_smo
+ {
+ public:
+ double penalty;
+ double C;
+
+ double operator() (
+ const matrix<double,0,1>& alpha
+ ) const
+ {
+
+ double obj = 0.5* trans(alpha)*Q*alpha - trans(alpha)*b;
+ double c1 = pow(sum(alpha)-C,2);
+ double c2 = sum(pow(pointwise_multiply(alpha, alpha<0), 2));
+
+ obj += penalty*(c1 + c2);
+
+ return obj;
+ }
+
+ matrix<double> Q, b;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ class test_smo_derivative
+ {
+ public:
+ double penalty;
+ double C;
+
+ matrix<double,0,1> operator() (
+ const matrix<double,0,1>& alpha
+ ) const
+ {
+
+ matrix<double,0,1> obj = Q*alpha - b;
+ matrix<double,0,1> c1 = uniform_matrix<double>(alpha.size(),1, 2*(sum(alpha)-C));
+ matrix<double,0,1> c2 = 2*pointwise_multiply(alpha, alpha<0);
+
+ return obj + penalty*(c1 + c2);
+ }
+
+ matrix<double> Q, b;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ double compute_objective_value (
+ const matrix<double,0,1>& w,
+ const matrix<double>& A,
+ const matrix<double,0,1>& b,
+ const double C
+ )
+ {
+ return 0.5*dot(w,w) + C*max(trans(A)*w + b);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_qp4_test1()
+ {
+ matrix<double> A(3,2);
+ A = 1,2,
+ -3,1,
+ 6,7;
+
+ matrix<double,0,1> b(2);
+ b = 1,
+ 2;
+
+ const double C = 2;
+
+ matrix<double,0,1> alpha(2), true_alpha(2), d(3), lambda;
+ alpha = C/2, C/2;
+ d = 0;
+
+ solve_qp4_using_smo(A, tmp(trans(A)*A), b, d, alpha, lambda, 1e-9, 800);
+ matrix<double,0,1> w = lowerbound(-A*alpha, 0);
+
+ dlog << LINFO << "*******************************************************";
+
+ dlog << LINFO << "w: " << trans(w);
+
+ dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C);
+ w = 0;
+ dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C);
+
+ dlog << LINFO << "alpha: " << trans(alpha);
+ true_alpha = 0, 2;
+ dlog << LINFO << "true alpha: "<< trans(true_alpha);
+
+ dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha));
+ DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_qp4_test2()
+ {
+ matrix<double> A(3,2);
+ A = 1,2,
+ 3,-1,
+ 6,7;
+
+ matrix<double,0,1> b(2);
+ b = 1,
+ 2;
+
+ const double C = 2;
+
+ matrix<double,0,1> alpha(2), true_alpha(2), d(3), lambda;
+ alpha = C/2, C/2;
+ d = 0;
+
+ solve_qp4_using_smo(A, tmp(trans(A)*A), b, d, alpha, lambda, 1e-9, 800);
+ matrix<double,0,1> w = lowerbound(-A*alpha, 0);
+
+ dlog << LINFO << "*******************************************************";
+
+ dlog << LINFO << "w: " << trans(w);
+
+ dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C);
+ w = 0, 0.25, 0;
+ dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C);
+
+ dlog << LINFO << "alpha: " << trans(alpha);
+ true_alpha = 0.43750, 1.56250;
+ dlog << LINFO << "true alpha: "<< trans(true_alpha);
+
+ dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha));
+ DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_qp4_test3()
+ {
+ matrix<double> A(3,2);
+ A = 1,2,
+ -3,-1,
+ 6,7;
+
+ matrix<double,0,1> b(2);
+ b = 1,
+ 2;
+
+ const double C = 2;
+
+ matrix<double,0,1> alpha(2), true_alpha(2), d(3), lambda;
+ alpha = C/2, C/2;
+ d = 0;
+
+ solve_qp4_using_smo(A, tmp(trans(A)*A), b, d, alpha, lambda, 1e-9, 800);
+ matrix<double,0,1> w = lowerbound(-A*alpha, 0);
+
+ dlog << LINFO << "*******************************************************";
+
+ dlog << LINFO << "w: " << trans(w);
+
+ dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C);
+ w = 0, 2, 0;
+ dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C);
+
+ dlog << LINFO << "alpha: " << trans(alpha);
+ true_alpha = 0, 2;
+ dlog << LINFO << "true alpha: "<< trans(true_alpha);
+
+ dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha));
+ DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_qp4_test5()
+ {
+ matrix<double> A(3,3);
+ A = 1,2,4,
+ 3,1,6,
+ 6,7,-2;
+
+ matrix<double,0,1> b(3);
+ b = 1,
+ 2,
+ 3;
+
+ const double C = 2;
+
+ matrix<double,0,1> alpha(3), true_alpha(3), d(3), lambda;
+ alpha = C/2, C/2, 0;
+ d = 0;
+
+ solve_qp4_using_smo(A, tmp(trans(A)*A), b, d, alpha, lambda, 1e-9, 800);
+ matrix<double,0,1> w = lowerbound(-A*alpha, 0);
+
+
+ dlog << LINFO << "*******************************************************";
+
+ dlog << LINFO << "w: " << trans(w);
+
+ dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C);
+ w = 0, 0, 0.11111111111111111111;
+ dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C);
+
+ dlog << LINFO << "alpha: " << trans(alpha);
+ true_alpha = 0, 0.432098765432099, 1.567901234567901;
+ dlog << LINFO << "true alpha: "<< trans(true_alpha);
+
+ dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha));
+ DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_qp4_test4()
+ {
+ matrix<double> A(3,2);
+ A = 1,2,
+ 3,1,
+ 6,7;
+
+ matrix<double,0,1> b(2);
+ b = 1,
+ 2;
+
+ const double C = 2;
+
+ matrix<double,0,1> alpha(2), d(3), lambda;
+ alpha = C/2, C/2;
+
+ solve_qp4_using_smo(A, tmp(trans(A)*A), b, d, alpha, lambda, 1e-9, 800);
+ matrix<double,0,1> w = lowerbound(-A*alpha, 0);
+
+ dlog << LINFO << "*******************************************************";
+
+ dlog << LINFO << "w: " << trans(w);
+
+ const double computed_obj = compute_objective_value(w,A,b,C);
+ w = 0, 0, 0;
+ const double true_obj = compute_objective_value(w,A,b,C);
+ dlog << LINFO << "computed obj: "<< computed_obj;
+ dlog << LINFO << "with true w obj: "<< true_obj;
+
+ DLIB_TEST_MSG(abs(computed_obj - true_obj) < 1e-8, abs(computed_obj - true_obj));
+ }
+
+ void test_qp4_test6()
+ {
+ matrix<double> A(3,3);
+ A = 1,2,4,
+ 3,1,6,
+ 6,7,-2;
+
+ matrix<double,0,1> b(3);
+ b = -1,
+ -2,
+ -3;
+
+ const double C = 2;
+
+ matrix<double,0,1> alpha(3), d(3), lambda;
+ d = 0;
+ alpha = C/2, C/2, 0;
+
+ unsigned long iters = solve_qp4_using_smo(A, tmp(trans(A)*A), b, d, alpha, lambda, 1e-9, 3000);
+ matrix<double,0,1> w = lowerbound(-A*alpha, 0);
+
+ dlog << LINFO << "*******************************************************";
+
+ dlog << LINFO << "alpha: " << trans(alpha);
+ dlog << LINFO << "lambda: " << trans(lambda);
+ dlog << LINFO << "w: " << trans(w);
+
+
+ const double computed_obj = compute_objective_value(w,A,b,C);
+ w = 0, 0, 0;
+ const double true_obj = compute_objective_value(w,A,b,C);
+ dlog << LINFO << "computed obj: "<< computed_obj;
+ dlog << LINFO << "with true w obj: "<< true_obj;
+
+ DLIB_TEST_MSG(abs(computed_obj - true_obj) < 1e-8,
+ "computed_obj: "<< computed_obj << " true_obj: " << true_obj << " delta: "<< abs(computed_obj - true_obj)
+ << " iters: " << iters
+ << "\n alpha: " << trans(alpha)
+ << " lambda: " << trans(lambda)
+ );
+ }
+
+ void test_qp4_test7()
+ {
+ matrix<double> A(3,3);
+ A = -1,2,4,
+ -3,1,6,
+ -6,7,-2;
+
+ matrix<double,0,1> b(3);
+ b = -1,
+ -2,
+ 3;
+
+ matrix<double> Q(3,3);
+ Q = 4,-5,6,
+ 1,-4,2,
+ -9,-4,5;
+ Q = Q*trans(Q);
+
+ const double C = 2;
+
+ matrix<double,0,1> alpha(3), true_alpha(3), d(3), lambda;
+ alpha = C/2, C/2, 0;
+ d = 0;
+
+ solve_qp4_using_smo(A, Q, b, d, alpha, lambda, 1e-9, 800);
+
+ dlog << LINFO << "*******************************************************";
+
+ dlog << LINFO << "alpha: " << trans(alpha);
+ true_alpha = 0, 2, 0;
+ dlog << LINFO << "true alpha: "<< trans(true_alpha);
+
+ dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha));
+ DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_solve_qp4_using_smo()
+ {
+ test_qp4_test1();
+ test_qp4_test2();
+ test_qp4_test3();
+ test_qp4_test4();
+ test_qp4_test5();
+ test_qp4_test6();
+ test_qp4_test7();
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ double max_distance_to(
+ const std::vector<matrix<double,0,1>>& a,
+ const std::vector<matrix<double,0,1>>& b
+ )
+ {
+ double best_dist = 0;
+ for (auto&& aa : a)
+ {
+ for (auto&& bb : b)
+ {
+ double dist = length(aa-bb);
+ if (dist > best_dist)
+ best_dist = dist;
+ }
+ }
+ return best_dist;
+ }
+
+ double min_distance_to(
+ const std::vector<matrix<double,0,1>>& a,
+ const std::vector<matrix<double,0,1>>& b
+ )
+ {
+ double best_dist = std::numeric_limits<double>::infinity();
+ for (auto&& aa : a)
+ {
+ for (auto&& bb : b)
+ {
+ double dist = length(aa-bb);
+ if (dist < best_dist)
+ best_dist = dist;
+ }
+ }
+ return best_dist;
+ }
+
+ double min_distance_to(
+ const std::vector<matrix<double,0,1>>& s,
+ const matrix<double,0,1>& v
+ )
+ {
+ double best_dist = std::numeric_limits<double>::infinity();
+ for (auto& x : s)
+ {
+ double dist = length(v-x);
+ if (dist < best_dist)
+ {
+ best_dist = dist;
+ }
+ }
+ return best_dist;
+ }
+
+ double max_distance_to(
+ const std::vector<matrix<double,0,1>>& s,
+ const matrix<double,0,1>& v
+ )
+ {
+ double best_dist = 0;
+ for (auto& x : s)
+ {
+ double dist = length(v-x);
+ if (dist > best_dist)
+ {
+ best_dist = dist;
+ }
+ }
+ return best_dist;
+ }
+
+ void test_find_gap_between_convex_hulls()
+ {
+ print_spinner();
+ std::vector<matrix<double,0,1>> set1, set2;
+
+ const double dist_thresh = 5.47723;
+
+ // generate two groups of points that are pairwise close within each set and
+ // pairwise far apart between each set, according to dist_thresh distance threshold.
+ bool which = true;
+ for (size_t i = 0; i < 10000; ++i)
+ {
+ matrix<double,0,1> v = gaussian_randm(15,1,i);
+ const auto min_dist1 = min_distance_to(set1,v);
+ const auto min_dist2 = min_distance_to(set2,v);
+ const auto max_dist1 = max_distance_to(set1,v);
+ const auto max_dist2 = max_distance_to(set2,v);
+ if (which)
+ {
+ if ((set1.size()==0 || max_dist1 < dist_thresh) && min_dist2 > dist_thresh )
+ {
+ set1.push_back(v);
+ which = !which;
+ }
+ }
+ else
+ {
+ if ((set2.size()==0 || max_dist2 < dist_thresh) && min_dist1 > dist_thresh)
+ {
+ set2.push_back(v);
+ which = !which;
+ }
+ }
+ }
+
+ dlog << LINFO << "set1.size(): "<< set1.size();
+ dlog << LINFO << "set2.size(): "<< set2.size();
+
+
+ // make sure we generated the points correctly.
+ dlog << LINFO << "dist_thresh: "<< dist_thresh;
+ dlog << LINFO << "max distance between set1 and set1: "<< max_distance_to(set1,set1);
+ dlog << LINFO << "max distance between set2 and set2: "<< max_distance_to(set2,set2);
+ DLIB_TEST(max_distance_to(set1,set1) < dist_thresh);
+ DLIB_TEST(max_distance_to(set2,set2) < dist_thresh);
+ dlog << LINFO << "min distance between set2 and set1: "<< min_distance_to(set2,set1);
+ DLIB_TEST(min_distance_to(set2,set1) > dist_thresh);
+
+
+ // It is slightly counterintuitive but true that points picked using the above procedure
+ // will have elements of their convex hulls that are much closer together than
+ // dist_thresh, even though none of the vertices of the hulls are that close
+ // together. This is especially true in high dimensions. So let's use this to
+ // test find_gap_between_convex_hulls(). It should be able to find a pair of
+ // points in the convex hulls of our sets that are a lot closer together than
+ // dist_thresh.
+
+ // First we need to convert the vectors to matrices.
+ matrix<double> A, B;
+ A.set_size(set1[0].size(), set1.size());
+ B.set_size(set2[0].size(), set2.size());
+ for (long c = 0; c < A.nc(); ++c)
+ set_colm(A,c) = set1[c];
+ for (long c = 0; c < B.nc(); ++c)
+ set_colm(B,c) = set2[c];
+
+ matrix<double,0,1> c1, c2;
+ find_gap_between_convex_hulls(A, B, c1, c2, 0.0001);
+ // make sure c1 and c2 are convex combinations.
+ DLIB_TEST(abs(sum(c1)-1) < 1e-8);
+ DLIB_TEST(abs(sum(c2)-1) < 1e-8);
+ DLIB_TEST(min(c1) >= 0);
+ DLIB_TEST(min(c2) >= 0);
+
+ // now test that the points found are close together.
+ dlog << LINFO << "dist: "<< length(A*c1 - B*c2);
+ DLIB_TEST(length(A*c1 - B*c2) < 4);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_solve_qp_box_constrained_blockdiag()
+ {
+ dlib::rand rnd;
+ for (int iter = 0; iter < 50; ++iter)
+ {
+ print_spinner();
+
+ matrix<double> Q1, Q2;
+ matrix<double,0,1> b1, b2;
+
+ Q1 = randm(4,4,rnd); Q1 = Q1*trans(Q1);
+ Q2 = randm(4,4,rnd); Q2 = Q2*trans(Q2);
+ b1 = gaussian_randm(4,1, iter*2+0);
+ b2 = gaussian_randm(4,1, iter*2+1);
+
+ std::map<unordered_pair<size_t>, matrix<double,0,1>> offdiag;
+
+ if (rnd.get_random_gaussian() > 0)
+ offdiag[make_unordered_pair(0,0)] = randm(4,1,rnd);
+ if (rnd.get_random_gaussian() > 0)
+ offdiag[make_unordered_pair(1,0)] = randm(4,1,rnd);
+ if (rnd.get_random_gaussian() > 0)
+ offdiag[make_unordered_pair(1,1)] = randm(4,1,rnd);
+
+ std::vector<matrix<double>> Q_blocks = {Q1, Q2};
+ std::vector<matrix<double,0,1>> bs = {b1, b2};
+
+
+ // make the single big Q and b
+ matrix<double> Q = join_cols(join_rows(Q1, zeros_matrix(Q1)),
+ join_rows(zeros_matrix(Q2),Q2));
+ matrix<double,0,1> b = join_cols(b1,b2);
+ for (auto& p : offdiag)
+ {
+ long r = p.first.first;
+ long c = p.first.second;
+ set_subm(Q, 4*r,4*c, 4,4) += diagm(p.second);
+ if (c != r)
+ set_subm(Q, 4*c,4*r, 4,4) += diagm(p.second);
+ }
+
+
+ matrix<double,0,1> alpha = zeros_matrix(b);
+ matrix<double,0,1> lower = -10000*ones_matrix(b);
+ matrix<double,0,1> upper = 10000*ones_matrix(b);
+
+ auto iters = solve_qp_box_constrained(Q, b, alpha, lower, upper, 1e-9, 10000);
+ dlog << LINFO << "iters: "<< iters;
+ dlog << LINFO << "alpha: " << trans(alpha);
+
+ dlog << LINFO;
+
+ std::vector<matrix<double,0,1>> alphas(2);
+ alphas[0] = zeros_matrix<double>(4,1); alphas[1] = zeros_matrix<double>(4,1);
+
+ lower = -10000*ones_matrix(alphas[0]);
+ upper = 10000*ones_matrix(alphas[0]);
+ std::vector<matrix<double,0,1>> lowers = {lower,lower}, uppers = {upper, upper};
+ auto iters2 = solve_qp_box_constrained_blockdiag(Q_blocks, bs, offdiag, alphas, lowers, uppers, 1e-9, 10000);
+ dlog << LINFO << "iters2: "<< iters2;
+ dlog << LINFO << "alpha: " << trans(join_cols(alphas[0],alphas[1]));
+
+ dlog << LINFO << "obj1: "<< 0.5*trans(alpha)*Q*alpha + trans(b)*alpha;
+ dlog << LINFO << "obj2: "<< 0.5*trans(join_cols(alphas[0],alphas[1]))*Q*join_cols(alphas[0],alphas[1]) + trans(b)*join_cols(alphas[0],alphas[1]);
+ dlog << LINFO << "obj1-obj2: "<<(0.5*trans(alpha)*Q*alpha + trans(b)*alpha) - (0.5*trans(join_cols(alphas[0],alphas[1]))*Q*join_cols(alphas[0],alphas[1]) + trans(b)*join_cols(alphas[0],alphas[1]));
+
+ DLIB_TEST_MSG(max(abs(alpha - join_cols(alphas[0], alphas[1]))) < 1e-6, max(abs(alpha - join_cols(alphas[0], alphas[1]))));
+
+ DLIB_TEST(iters == iters2);
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_solve_qp_box_constrained_blockdiag_compact(dlib::rand& rnd, double percent_off_diag_present)
+ {
+ print_spinner();
+
+ dlog << LINFO << "test_solve_qp_box_constrained_blockdiag_compact(), percent_off_diag_present==" << percent_off_diag_present;
+
+ std::map<unordered_pair<size_t>, matrix<double,0,1>> offdiag;
+ std::vector<matrix<double>> Q_blocks;
+ std::vector<matrix<double,0,1>> bs;
+
+ const long num_blocks = 20;
+ const long dims = 4;
+ const double lambda = 10;
+ for (long i = 0; i < num_blocks; ++i)
+ {
+ matrix<double> Q1;
+ matrix<double,0,1> b1;
+ Q1 = randm(dims,dims,rnd); Q1 = Q1*trans(Q1);
+ b1 = gaussian_randm(dims,1, i);
+
+ Q_blocks.push_back(Q1);
+ bs.push_back(b1);
+
+ // test with some graph regularization terms
+ for (long j = 0; j < num_blocks; ++j)
+ {
+ if (rnd.get_random_double() < percent_off_diag_present)
+ {
+ if (i==j)
+ offdiag[make_unordered_pair(i,j)] = (num_blocks-1)*lambda*rnd.get_random_double()*ones_matrix<double>(dims,1);
+ else
+ offdiag[make_unordered_pair(i,j)] = -lambda*rnd.get_random_double()*ones_matrix<double>(dims,1);
+ }
+ }
+ }
+
+ // build out the dense version of the QP so we can test it against the dense solver.
+ matrix<double> Q(num_blocks*dims, num_blocks*dims);
+ Q = 0;
+ matrix<double,0,1> b(num_blocks*dims);
+ for (long i = 0; i < num_blocks; ++i)
+ {
+ set_subm(Q,i*dims,i*dims,dims,dims) = Q_blocks[i];
+ set_subm(b,i*dims,0,dims,1) = bs[i];
+ }
+ for (auto& p : offdiag)
+ {
+ long r = p.first.first;
+ long c = p.first.second;
+ set_subm(Q, dims*r,dims*c, dims,dims) += diagm(p.second);
+ if (c != r)
+ set_subm(Q, dims*c,dims*r, dims,dims) += diagm(p.second);
+ }
+
+
+
+ matrix<double,0,1> alpha = zeros_matrix<double>(dims*num_blocks,1);
+ matrix<double,0,1> lower = -10000*ones_matrix<double>(dims*num_blocks,1);
+ matrix<double,0,1> upper = 10000*ones_matrix<double>(dims*num_blocks,1);
+
+ auto iters = solve_qp_box_constrained(Q, b, alpha, lower, upper, 1e-9, 20000);
+ dlog << LINFO << "iters: "<< iters;
+
+
+ matrix<double,0,1> init_alpha = zeros_matrix(bs[0]);
+ lower = -10000*ones_matrix(bs[0]);
+ upper = 10000*ones_matrix(bs[0]);
+
+ std::vector<matrix<double,0,1>> alphas(num_blocks, init_alpha);
+ std::vector<matrix<double,0,1>> lowers(num_blocks, lower);
+ std::vector<matrix<double,0,1>> uppers(num_blocks, upper);
+
+ auto iters2 = solve_qp_box_constrained_blockdiag(Q_blocks, bs, offdiag, alphas, lowers, uppers, 1e-9, 20000);
+ dlog << LINFO << "iters2: "<< iters2;
+
+
+ const matrix<double> refalpha = reshape(alpha, num_blocks, dims);
+
+ // now make sure the two solvers agree on the outputs.
+ for (long r = 0; r < num_blocks; ++r)
+ {
+ for (long c = 0; c < dims; ++c)
+ {
+ DLIB_TEST_MSG(std::abs(refalpha(r,c) - alphas[r](c)) < 1e-6, std::abs(refalpha(r,c) - alphas[r](c)));
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class opt_qp_solver_tester : public tester
+ {
+ /*
+ The idea here is just to solve the same problem with two different
+ methods and check that they basically agree. The SMO solver should be
+ very accurate but for this problem the BFGS solver is relatively
+ inaccurate. So this test is really just a sanity check on the SMO
+ solver.
+ */
+ public:
+ opt_qp_solver_tester (
+ ) :
+ tester ("test_opt_qp_solver",
+ "Runs tests on the solve_qp_using_smo component.")
+ {
+ thetime = time(0);
+ }
+
+ time_t thetime;
+ dlib::rand rnd;
+
+ void perform_test(
+ )
+ {
+ print_spinner();
+ test_solve_qp4_using_smo();
+ print_spinner();
+
+ ++thetime;
+ //dlog << LINFO << "time seed: " << thetime;
+ //rnd.set_seed(cast_to_string(thetime));
+
+ running_stats<double> rs;
+
+ for (int i = 0; i < 40; ++i)
+ {
+ for (long dims = 1; dims < 6; ++dims)
+ {
+ rs.add(do_the_test(dims, 1.0));
+ }
+ }
+
+ for (int i = 0; i < 40; ++i)
+ {
+ for (long dims = 1; dims < 6; ++dims)
+ {
+ rs.add(do_the_test(dims, 5.0));
+ }
+ }
+
+ dlog << LINFO << "disagreement mean: " << rs.mean();
+ dlog << LINFO << "disagreement stddev: " << rs.stddev();
+ DLIB_TEST_MSG(rs.mean() < 0.001, rs.mean());
+ DLIB_TEST_MSG(rs.stddev() < 0.001, rs.stddev());
+
+
+ test_find_gap_between_convex_hulls();
+ test_solve_qp_box_constrained_blockdiag();
+
+ // try a range of off diagonal sparseness. We do this to make sure we exercise both
+ // the compact and sparse code paths within the solver.
+ test_solve_qp_box_constrained_blockdiag_compact(rnd, 0.001);
+ test_solve_qp_box_constrained_blockdiag_compact(rnd, 0.01);
+ test_solve_qp_box_constrained_blockdiag_compact(rnd, 0.04);
+ test_solve_qp_box_constrained_blockdiag_compact(rnd, 0.10);
+ test_solve_qp_box_constrained_blockdiag_compact(rnd, 0.50);
+ test_solve_qp_box_constrained_blockdiag_compact(rnd, 1.00);
+ }
+
+ double do_the_test (
+ const long dims,
+ double C
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "dims: " << dims;
+ dlog << LINFO << "testing with C == " << C;
+ test_smo test;
+
+ test.Q = randm(dims, dims, rnd);
+ test.Q = trans(test.Q)*test.Q;
+ test.b = randm(dims,1, rnd);
+ test.C = C;
+
+ test_smo_derivative der;
+ der.Q = test.Q;
+ der.b = test.b;
+ der.C = test.C;
+
+
+ matrix<double,0,1> x(dims), alpha(dims);
+
+
+ test.penalty = 20000;
+ der.penalty = test.penalty;
+
+ alpha = C/alpha.size();
+ x = alpha;
+
+ const unsigned long max_iter = 400000;
+ solve_qp_using_smo(test.Q, test.b, alpha, 0.00000001, max_iter);
+ DLIB_TEST_MSG(abs(sum(alpha) - C) < 1e-13, abs(sum(alpha) - C) );
+ dlog << LTRACE << "alpha: " << alpha;
+ dlog << LINFO << "SMO: true objective: "<< 0.5*trans(alpha)*test.Q*alpha - trans(alpha)*test.b;
+
+
+ double obj = find_min(bfgs_search_strategy(),
+ objective_delta_stop_strategy(1e-13, 5000),
+ test,
+ der,
+ x,
+ -10);
+
+
+ dlog << LINFO << "BFGS: objective: " << obj;
+ dlog << LINFO << "BFGS: true objective: "<< 0.5*trans(x)*test.Q*x - trans(x)*test.b;
+ dlog << LINFO << "sum(x): " << sum(x);
+ dlog << LINFO << x;
+
+ double disagreement = max(abs(x-alpha));
+ dlog << LINFO << "Disagreement: " << disagreement;
+ return disagreement;
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/optimization.cpp b/ml/dlib/dlib/test/optimization.cpp
new file mode 100644
index 000000000..b47449abe
--- /dev/null
+++ b/ml/dlib/dlib/test/optimization.cpp
@@ -0,0 +1,1231 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include "optimization_test_functions.h"
+#include <dlib/optimization.h>
+#include <dlib/statistics.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.optimization");
+
+// ----------------------------------------------------------------------------------------
+
+ bool approx_equal (
+ double a,
+ double b
+ )
+ {
+ return std::abs(a - b) < 100*std::numeric_limits<double>::epsilon();
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ long total_count = 0;
+
+
+ template <typename T>
+ double apq ( const T& x)
+ {
+ DLIB_ASSERT(x.nr() > 1 && x.nc() == 1,"");
+ COMPILE_TIME_ASSERT(is_matrix<T>::value);
+ double temp = 0;
+ for (long r = 0; r < x.nr(); ++r)
+ {
+ temp += (r+1)*x(r)*x(r);
+ }
+
+ ++total_count;
+
+ return temp + 1/100.0*(x(0) + x(x.nr()-1))*(x(0) + x(x.nr()-1));
+ }
+
+ template <typename T>
+ T der_apq ( const T& x)
+ {
+ DLIB_ASSERT(x.nr() > 1 && x.nc() == 1,"");
+ COMPILE_TIME_ASSERT(is_matrix<T>::value);
+ T temp(x.nr());
+ for (long r = 0; r < x.nr(); ++r)
+ {
+ temp(r) = 2*(r+1)*x(r) ;
+ }
+
+ temp(0) += 1/50.0*(x(0) + x(x.nr()-1));
+ temp(x.nr()-1) += 1/50.0*(x(0) + x(x.nr()-1));
+
+ ++total_count;
+
+ return temp;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ // Rosenbrock's function. minimum at (1,1)
+ double rosen ( const matrix<double,2,1>& x)
+ {
+ ++total_count;
+ return 100*pow(x(1) - x(0)*x(0),2) + pow(1 - x(0),2);
+ }
+
+ matrix<double,2,1> der_rosen ( const matrix<double,2,1>& x)
+ {
+ ++total_count;
+ matrix<double,2,1> res;
+ res(0) = -400*x(0)*(x(1)-x(0)*x(0)) - 2*(1-x(0));
+ res(1) = 200*(x(1)-x(0)*x(0));
+ return res;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ // negative of Rosenbrock's function. minimum at (1,1)
+ double neg_rosen ( const matrix<double,2,1>& x)
+ {
+ ++total_count;
+ return -(100*pow(x(1) - x(0)*x(0),2) + pow(1 - x(0),2));
+ }
+
+ matrix<double,2,1> der_neg_rosen ( const matrix<double,2,1>& x)
+ {
+ ++total_count;
+ matrix<double,2,1> res;
+ res(0) = -400*x(0)*(x(1)-x(0)*x(0)) - 2*(1-x(0));
+ res(1) = 200*(x(1)-x(0)*x(0));
+ return -res;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ double simple ( const matrix<double,2,1>& x)
+ {
+ ++total_count;
+ return 10*x(0)*x(0) + x(1)*x(1);
+ }
+
+ matrix<double,2,1> der_simple ( const matrix<double,2,1>& x)
+ {
+ ++total_count;
+ matrix<double,2,1> res;
+ res(0) = 20*x(0);
+ res(1) = 2*x(1);
+ return res;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ double powell ( const matrix<double,4,1>& x)
+ {
+ ++total_count;
+ return pow(x(0) + 10*x(1),2) +
+ pow(std::sqrt(5.0)*(x(2) - x(3)),2) +
+ pow((x(1) - 2*x(2))*(x(1) - 2*x(2)),2) +
+ pow(std::sqrt(10.0)*(x(0) - x(3))*(x(0) - x(3)),2);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+// a simple function with a minimum at zero
+ double single_variable_function ( double x)
+ {
+ ++total_count;
+ return 3*x*x + 5;
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ void test_apq (
+ const matrix<double,0,1> p
+ )
+ {
+ typedef matrix<double,0,1> T;
+ const double eps = 1e-12;
+ const double minf = -10;
+ matrix<double,0,1> x(p.nr()), opt(p.nr());
+ set_all_elements(opt, 0);
+ double val = 0;
+
+ if (p.size() < 20)
+ dlog << LINFO << "testing with apq and the start point: " << trans(p);
+ else
+ dlog << LINFO << "testing with apq and a big vector with " << p.size() << " components.";
+
+ // don't use bfgs on really large vectors
+ if (p.size() < 20)
+ {
+ total_count = 0;
+ x = p;
+ val = find_min(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min() bgfs: got apq in " << total_count;
+
+ total_count = 0;
+ x = p;
+ find_min(bfgs_search_strategy(),
+ gradient_norm_stop_strategy(),
+ wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ dlog << LINFO << "find_min() bgfs(gn): got apq in " << total_count;
+ }
+
+
+ if (p.size() < 100)
+ {
+ total_count = 0;
+ x = p;
+ val=find_min_bobyqa(wrap_function(apq<T>), x, 2*x.size()+1,
+ uniform_matrix<double>(x.size(),1,-1e100),
+ uniform_matrix<double>(x.size(),1,1e100),
+ (max(abs(x))+1)/10,
+ 1e-6,
+ 10000);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min_bobyqa(): got apq in " << total_count;
+ }
+
+ total_count = 0;
+ x = p;
+ val=find_min(lbfgs_search_strategy(10),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min() lbgfs-10: got apq in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(lbfgs_search_strategy(1),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min() lbgfs-1: got apq in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min() cg: got apq in " << total_count;
+
+
+ // don't do approximate derivative tests if the input point is really long
+ if (p.size() < 20)
+ {
+ total_count = 0;
+ x = p;
+ val=find_min(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), derivative(wrap_function(apq<T>)), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min() bfgs: got apq/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), derivative(wrap_function(apq<T>)), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min() cg: got apq/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min() bfgs: got apq/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(lbfgs_search_strategy(10),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ dlog << LINFO << "find_min() lbfgs-10: got apq/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ wrap_function(apq<T>), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , apq(x)));
+ dlog << LINFO << "find_min() cg: got apq/noder2 in " << total_count;
+ }
+ }
+
+ void test_powell (
+ const matrix<double,4,1> p
+ )
+ {
+ const double eps = 1e-15;
+ const double minf = -1;
+ matrix<double,4,1> x, opt;
+ opt(0) = 0;
+ opt(1) = 0;
+ opt(2) = 0;
+ opt(3) = 0;
+
+ double val = 0;
+
+ dlog << LINFO << "testing with powell and the start point: " << trans(p);
+
+ /*
+ total_count = 0;
+ x = p;
+ val=find_min(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ powell, derivative(powell,1e-8), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-2),opt-x);
+ DLIB_TEST(approx_equal(val , powell(x)));
+ dlog << LINFO << "find_min() bfgs: got powell/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ powell, derivative(powell,1e-9), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-2),opt-x);
+ DLIB_TEST(approx_equal(val , powell(x)));
+ dlog << LINFO << "find_min() cg: got powell/noder in " << total_count;
+ */
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ powell, x, minf, 1e-10);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x);
+ DLIB_TEST(approx_equal(val , powell(x)));
+ dlog << LINFO << "find_min() bfgs: got powell/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(lbfgs_search_strategy(4),
+ objective_delta_stop_strategy(eps),
+ powell, x, minf, 1e-10);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x);
+ DLIB_TEST(approx_equal(val , powell(x)));
+ dlog << LINFO << "find_min() lbfgs-4: got powell/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(lbfgs_search_strategy(4),
+ gradient_norm_stop_strategy(),
+ powell, x, minf, 1e-10);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x);
+ DLIB_TEST(approx_equal(val , powell(x)));
+ dlog << LINFO << "find_min() lbfgs-4(gn): got powell/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ powell, x, minf, 1e-10);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x);
+ DLIB_TEST(approx_equal(val , powell(x)));
+ dlog << LINFO << "find_min() cg: got powell/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_bobyqa(powell, x, 2*x.size()+1,
+ uniform_matrix<double>(x.size(),1,-1e100),
+ uniform_matrix<double>(x.size(),1,1e100),
+ (max(abs(x))+1)/10,
+ 1e-8,
+ 10000);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-3),opt-x);
+ DLIB_TEST(approx_equal(val , powell(x)));
+ dlog << LINFO << "find_min_bobyqa(): got powell in " << total_count;
+
+ }
+
+
+
+ void test_simple (
+ const matrix<double,2,1> p
+ )
+ {
+ const double eps = 1e-12;
+ const double minf = -10000;
+ matrix<double,2,1> x, opt;
+ opt(0) = 0;
+ opt(1) = 0;
+ double val = 0;
+
+ dlog << LINFO << "testing with simple and the start point: " << trans(p);
+
+ total_count = 0;
+ x = p;
+ val=find_min(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ simple, der_simple, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() bfgs: got simple in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(bfgs_search_strategy(),
+ gradient_norm_stop_strategy(),
+ simple, der_simple, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() bfgs(gn): got simple in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(lbfgs_search_strategy(3),
+ objective_delta_stop_strategy(eps),
+ simple, der_simple, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() lbfgs-3: got simple in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ simple, der_simple, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() cg: got simple in " << total_count;
+
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ simple, derivative(simple), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() bfgs: got simple/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(lbfgs_search_strategy(8),
+ objective_delta_stop_strategy(eps),
+ simple, derivative(simple), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() lbfgs-8: got simple/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ simple, derivative(simple), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() cg: got simple/noder in " << total_count;
+
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ simple, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() bfgs: got simple/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(lbfgs_search_strategy(6),
+ objective_delta_stop_strategy(eps),
+ simple, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() lbfgs-6: got simple/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ simple, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min() cg: got simple/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_bobyqa(simple, x, 2*x.size()+1,
+ uniform_matrix<double>(x.size(),1,-1e100),
+ uniform_matrix<double>(x.size(),1,1e100),
+ (max(abs(x))+1)/10,
+ 1e-6,
+ 10000);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , simple(x)));
+ dlog << LINFO << "find_min_bobyqa(): got simple in " << total_count;
+
+ }
+
+
+ void test_rosen (
+ const matrix<double,2,1> p
+ )
+ {
+ const double eps = 1e-15;
+ const double minf = -10;
+ matrix<double,2,1> x, opt;
+ opt(0) = 1;
+ opt(1) = 1;
+
+ double val = 0;
+
+ dlog << LINFO << "testing with rosen and the start point: " << trans(p);
+
+ total_count = 0;
+ x = p;
+ val=find_min(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ rosen, der_rosen, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min() bfgs: got rosen in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(bfgs_search_strategy(),
+ gradient_norm_stop_strategy(),
+ rosen, der_rosen, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min() bfgs(gn): got rosen in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(lbfgs_search_strategy(20),
+ objective_delta_stop_strategy(eps),
+ rosen, der_rosen, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min() lbfgs-20: got rosen in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ rosen, der_rosen, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min() cg: got rosen in " << total_count;
+
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ rosen, derivative(rosen,1e-5), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min() bfgs: got rosen/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(lbfgs_search_strategy(5),
+ objective_delta_stop_strategy(eps),
+ rosen, derivative(rosen,1e-5), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min() lbfgs-5: got rosen/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ rosen, derivative(rosen,1e-5), x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min() cg: got rosen/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_min_using_approximate_derivatives(cg_search_strategy(),
+ objective_delta_stop_strategy(eps),
+ rosen, x, minf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min() cg: got rosen/noder2 in " << total_count;
+
+
+ if (max(abs(p)) < 1000)
+ {
+ total_count = 0;
+ x = p;
+ val=find_min_bobyqa(rosen, x, 2*x.size()+1,
+ uniform_matrix<double>(x.size(),1,-1e100),
+ uniform_matrix<double>(x.size(),1,1e100),
+ (max(abs(x))+1)/10,
+ 1e-6,
+ 10000);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , rosen(x)));
+ dlog << LINFO << "find_min_bobyqa(): got rosen in " << total_count;
+ }
+ }
+
+
+ void test_neg_rosen (
+ const matrix<double,2,1> p
+ )
+ {
+ const double eps = 1e-15;
+ const double maxf = 10;
+ matrix<double,2,1> x, opt;
+ opt(0) = 1;
+ opt(1) = 1;
+
+ double val = 0;
+
+ dlog << LINFO << "testing with neg_rosen and the start point: " << trans(p);
+
+ total_count = 0;
+ x = p;
+ val=find_max(
+ bfgs_search_strategy(),
+ objective_delta_stop_strategy(eps), neg_rosen, der_neg_rosen, x, maxf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
+ DLIB_TEST(approx_equal(val , neg_rosen(x)));
+ dlog << LINFO << "find_max() bfgs: got neg_rosen in " << total_count;
+
+ total_count = 0;
+ x = p;
+ val=find_max(
+ lbfgs_search_strategy(5),
+ objective_delta_stop_strategy(eps), neg_rosen, der_neg_rosen, x, maxf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
+ DLIB_TEST(approx_equal(val , neg_rosen(x)));
+ dlog << LINFO << "find_max() lbfgs-5: got neg_rosen in " << total_count;
+
+ total_count = 0;
+ x = p;
+ val=find_max(
+ lbfgs_search_strategy(5),
+ objective_delta_stop_strategy(eps), neg_rosen, derivative(neg_rosen), x, maxf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
+ DLIB_TEST(approx_equal(val , neg_rosen(x)));
+ dlog << LINFO << "find_max() lbfgs-5: got neg_rosen/noder in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_max_using_approximate_derivatives(
+ cg_search_strategy(),
+ objective_delta_stop_strategy(eps), neg_rosen, x, maxf);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
+ DLIB_TEST(approx_equal(val , neg_rosen(x)));
+ dlog << LINFO << "find_max() cg: got neg_rosen/noder2 in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ val=find_max_bobyqa(neg_rosen, x, 2*x.size()+1,
+ uniform_matrix<double>(x.size(),1,-1e100),
+ uniform_matrix<double>(x.size(),1,1e100),
+ (max(abs(x))+1)/10,
+ 1e-6,
+ 10000);
+ DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
+ DLIB_TEST(approx_equal(val , neg_rosen(x)));
+ dlog << LINFO << "find_max_bobyqa(): got neg_rosen in " << total_count;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_single_variable_function (
+ const double p
+ )
+ {
+ const double eps = 1e-7;
+
+
+ dlog << LINFO << "testing with single_variable_function and the start point: " << p;
+ double out, x;
+
+ total_count = 0;
+ x = p;
+ out = find_min_single_variable(single_variable_function, x, -1e100, 1e100, eps, 1000);
+ DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5);
+ DLIB_TEST_MSG(std::abs(x) < 1e-6, x);
+ dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count;
+
+
+ total_count = 0;
+ x = p;
+ out = -find_max_single_variable(negate_function(single_variable_function), x, -1e100, 1e100, eps, 1000);
+ DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5);
+ DLIB_TEST_MSG(std::abs(x) < 1e-6, x);
+ dlog << LINFO << "find_max_single_variable(): got single_variable_function in " << total_count;
+
+
+ if (p > 0)
+ {
+ total_count = 0;
+ x = p;
+ out = find_min_single_variable(single_variable_function, x, -1e-4, 1e100, eps, 1000);
+ DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5);
+ DLIB_TEST_MSG(std::abs(x) < 1e-6, x);
+ dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count;
+
+
+ if (p > 3)
+ {
+ total_count = 0;
+ x = p;
+ out = -find_max_single_variable(negate_function(single_variable_function), x, 3, 1e100, eps, 1000);
+ DLIB_TEST_MSG(std::abs(out - (3*3*3+5)) < 1e-6, out-(3*3*3+5));
+ DLIB_TEST_MSG(std::abs(x-3) < 1e-6, x);
+ dlog << LINFO << "find_max_single_variable(): got single_variable_function in " << total_count;
+ }
+ }
+
+ if (p < 0)
+ {
+ total_count = 0;
+ x = p;
+ out = find_min_single_variable(single_variable_function, x, -1e100, 1e-4, eps, 1000);
+ DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5);
+ DLIB_TEST_MSG(std::abs(x) < 1e-6, x);
+ dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count;
+
+ if (p < -3)
+ {
+ total_count = 0;
+ x = p;
+ out = find_min_single_variable(single_variable_function, x, -1e100, -3, eps, 1000);
+ DLIB_TEST_MSG(std::abs(out - (3*3*3+5)) < 1e-6, out-(3*3*3+5));
+ DLIB_TEST_MSG(std::abs(x+3) < 1e-6, x);
+ dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count;
+ }
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void optimization_test (
+ )
+ /*!
+ ensures
+ - runs tests on the optimization stuff compliance with the specs
+ !*/
+ {
+ matrix<double,0,1> p;
+
+ print_spinner();
+
+ p.set_size(2);
+
+ // test with single_variable_function
+ test_single_variable_function(0);
+ test_single_variable_function(1);
+ test_single_variable_function(-10);
+ test_single_variable_function(-100);
+ test_single_variable_function(900.53);
+
+ // test with the rosen function
+ p(0) = 9;
+ p(1) = -4.9;
+ test_rosen(p);
+ test_neg_rosen(p);
+
+ p(0) = 0;
+ p(1) = 0;
+ test_rosen(p);
+
+ p(0) = 5323;
+ p(1) = 98248;
+ test_rosen(p);
+
+ // test with the simple function
+ p(0) = 1;
+ p(1) = 1;
+ test_simple(p);
+
+ p(0) = 0.5;
+ p(1) = -9;
+ test_simple(p);
+
+ p(0) = 645;
+ p(1) = 839485;
+ test_simple(p);
+
+ print_spinner();
+
+ // test with the apq function
+ p.set_size(5);
+
+ p(0) = 1;
+ p(1) = 1;
+ p(2) = 1;
+ p(3) = 1;
+ p(4) = 1;
+ test_apq(p);
+
+ p(0) = 1;
+ p(1) = 2;
+ p(2) = 3;
+ p(3) = 4;
+ p(4) = 5;
+ test_apq(p);
+
+ p(0) = 1;
+ p(1) = 2;
+ p(2) = -3;
+ p(3) = 4;
+ p(4) = 5;
+ test_apq(p);
+
+ print_spinner();
+
+ p(0) = 1;
+ p(1) = 2324;
+ p(2) = -3;
+ p(3) = 4;
+ p(4) = 534534;
+ test_apq(p);
+
+ p.set_size(10);
+ p(0) = 1;
+ p(1) = 2;
+ p(2) = -3;
+ p(3) = 4;
+ p(4) = 5;
+ p(5) = 1;
+ p(6) = 2;
+ p(7) = -3;
+ p(8) = 4;
+ p(9) = 5;
+ test_apq(p);
+
+ // test apq with a big vector
+ p.set_size(500);
+ dlib::rand rnd;
+ for (long i = 0; i < p.size(); ++i)
+ {
+ p(i) = rnd.get_random_double()*20 - 10;
+ }
+ test_apq(p);
+
+ print_spinner();
+
+ // test with the powell function
+ p.set_size(4);
+
+ p(0) = 3;
+ p(1) = -1;
+ p(2) = 0;
+ p(3) = 1;
+ test_powell(p);
+
+ {
+ matrix<double,2,1> m;
+ m(0) = -0.43;
+ m(1) = 0.919;
+ DLIB_TEST(dlib::equal(der_rosen(m) , derivative(rosen)(m),1e-5));
+
+ DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) -
+ make_line_search_function(derivative(rosen),m,m)(0)) < 1e-5,"");
+ DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) -
+ make_line_search_function(derivative(rosen),m,m)(1)) < 1e-5,"");
+
+ DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) -
+ make_line_search_function(der_rosen,m,m)(0)) < 1e-5,"");
+ DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) -
+ make_line_search_function(der_rosen,m,m)(1)) < 1e-5,"");
+ }
+ {
+ matrix<double,2,1> m;
+ m(0) = 1;
+ m(1) = 2;
+ DLIB_TEST(dlib::equal(der_rosen(m) , derivative(rosen)(m),1e-5));
+
+ DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) -
+ make_line_search_function(derivative(rosen),m,m)(0)) < 1e-5,"");
+ DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) -
+ make_line_search_function(derivative(rosen),m,m)(1)) < 1e-5,"");
+
+ DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) -
+ make_line_search_function(der_rosen,m,m)(0)) < 1e-5,"");
+ DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) -
+ make_line_search_function(der_rosen,m,m)(1)) < 1e-5,"");
+ }
+
+ {
+ matrix<double,2,1> m;
+ m = 1,2;
+ DLIB_TEST(std::abs(neg_rosen(m) - negate_function(rosen)(m) ) < 1e-16);
+ }
+
+ }
+
+ template <typename der_funct, typename T>
+ double unconstrained_gradient_magnitude (
+ const der_funct& grad,
+ const T& x,
+ const T& lower,
+ const T& upper
+ )
+ {
+ T g = grad(x);
+
+ double unorm = 0;
+
+ for (long i = 0; i < g.size(); ++i)
+ {
+ if (lower(i) < x(i) && x(i) < upper(i))
+ unorm += g(i)*g(i);
+ else if (x(i) == lower(i) && g(i) < 0)
+ unorm += g(i)*g(i);
+ else if (x(i) == upper(i) && g(i) > 0)
+ unorm += g(i)*g(i);
+ }
+
+ return unorm;
+ }
+
+ template <typename der_funct, typename T>
+ double unconstrained_gradient_magnitude_neg_funct (
+ const der_funct& grad,
+ const T& x,
+ const T& lower,
+ const T& upper
+ )
+ {
+ T g = grad(x);
+
+ double unorm = 0;
+
+ for (long i = 0; i < g.size(); ++i)
+ {
+ if (lower(i) < x(i) && x(i) < upper(i))
+ unorm += g(i)*g(i);
+ else if (x(i) == lower(i) && g(i) > 0)
+ unorm += g(i)*g(i);
+ else if (x(i) == upper(i) && g(i) < 0)
+ unorm += g(i)*g(i);
+ }
+
+ return unorm;
+ }
+
+ template <typename search_strategy_type>
+ double test_bound_solver_neg_rosen (dlib::rand& rnd, search_strategy_type search_strategy)
+ {
+ using namespace dlib::test_functions;
+ print_spinner();
+ matrix<double,2,1> starting_point, lower, upper, x;
+
+
+ // pick random bounds
+ lower = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1;
+ upper = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1;
+ while (upper(0) < lower(0)) upper(0) = rnd.get_random_gaussian()+1;
+ while (upper(1) < lower(1)) upper(1) = rnd.get_random_gaussian()+1;
+
+ starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0),
+ rnd.get_random_double()*(upper(1)-lower(1))+lower(1);
+
+ dlog << LINFO << "lower: "<< trans(lower);
+ dlog << LINFO << "upper: "<< trans(upper);
+ dlog << LINFO << "starting: "<< trans(starting_point);
+
+ x = starting_point;
+ double val = find_max_box_constrained(
+ search_strategy,
+ objective_delta_stop_strategy(1e-16, 500),
+ neg_rosen, der_neg_rosen, x,
+ lower,
+ upper
+ );
+
+ DLIB_TEST_MSG(std::abs(val - neg_rosen(x)) < 1e-11, std::abs(val - neg_rosen(x)));
+ dlog << LINFO << "neg_rosen solution:\n" << x;
+
+ dlog << LINFO << "neg_rosen gradient: "<< trans(der_neg_rosen(x));
+ const double gradient_residual = unconstrained_gradient_magnitude_neg_funct(der_neg_rosen, x, lower, upper);
+ dlog << LINFO << "gradient_residual: "<< gradient_residual;
+
+ return gradient_residual;
+ }
+
+ template <typename search_strategy_type>
+ double test_bound_solver_rosen (dlib::rand& rnd, search_strategy_type search_strategy)
+ {
+ using namespace dlib::test_functions;
+ print_spinner();
+ matrix<double,2,1> starting_point, lower, upper, x;
+
+
+ // pick random bounds and sometimes put the upper bound at zero so we can have
+ // a test where the optimal value has a bound active at 0 so make sure this case
+ // works properly.
+ if (rnd.get_random_double() > 0.2)
+ {
+ lower = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1;
+ upper = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1;
+ while (upper(0) < lower(0)) upper(0) = rnd.get_random_gaussian()+1;
+ while (upper(1) < lower(1)) upper(1) = rnd.get_random_gaussian()+1;
+ }
+ else
+ {
+ upper = 0,0;
+ if (rnd.get_random_double() > 0.5)
+ upper(0) = -rnd.get_random_double();
+ if (rnd.get_random_double() > 0.5)
+ upper(1) = -rnd.get_random_double();
+
+ lower = rnd.get_random_double()+1, rnd.get_random_double()+1;
+ lower = upper - lower;
+ }
+ const bool pick_uniform_bounds = rnd.get_random_double() > 0.9;
+ if (pick_uniform_bounds)
+ {
+ double x = rnd.get_random_gaussian()*2;
+ double y = rnd.get_random_gaussian()*2;
+ lower = min(x,y);
+ upper = max(x,y);
+ }
+
+ starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0),
+ rnd.get_random_double()*(upper(1)-lower(1))+lower(1);
+
+ dlog << LINFO << "lower: "<< trans(lower);
+ dlog << LINFO << "upper: "<< trans(upper);
+ dlog << LINFO << "starting: "<< trans(starting_point);
+
+ x = starting_point;
+ double val;
+ if (!pick_uniform_bounds)
+ {
+ val = find_min_box_constrained(
+ search_strategy,
+ objective_delta_stop_strategy(1e-16, 500),
+ rosen, der_rosen, x,
+ lower,
+ upper
+ );
+ }
+ else
+ {
+ val = find_min_box_constrained(
+ search_strategy,
+ objective_delta_stop_strategy(1e-16, 500),
+ rosen, der_rosen, x,
+ lower(0),
+ upper(0)
+ );
+ }
+
+
+ DLIB_TEST_MSG(std::abs(val - rosen(x)) < 1e-11, std::abs(val - rosen(x)));
+ dlog << LINFO << "rosen solution:\n" << x;
+
+ dlog << LINFO << "rosen gradient: "<< trans(der_rosen(x));
+ const double gradient_residual = unconstrained_gradient_magnitude(der_rosen, x, lower, upper);
+ dlog << LINFO << "gradient_residual: "<< gradient_residual;
+
+ return gradient_residual;
+ }
+
+ template <typename search_strategy_type>
+ double test_bound_solver_brown (dlib::rand& rnd, search_strategy_type search_strategy)
+ {
+ using namespace dlib::test_functions;
+ print_spinner();
+ matrix<double,4,1> starting_point(4), lower(4), upper(4), x;
+
+ const matrix<double,0,1> solution = brown_solution();
+
+ // pick random bounds
+ lower = rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian();
+ lower = lower*10 + solution;
+ upper = rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian();
+ upper = upper*10 + solution;
+ for (int i = 0; i < lower.size(); ++i)
+ {
+ if (upper(i) < lower(i))
+ swap(upper(i),lower(i));
+ }
+
+ starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0),
+ rnd.get_random_double()*(upper(1)-lower(1))+lower(1),
+ rnd.get_random_double()*(upper(2)-lower(2))+lower(2),
+ rnd.get_random_double()*(upper(3)-lower(3))+lower(3);
+
+ dlog << LINFO << "lower: "<< trans(lower);
+ dlog << LINFO << "upper: "<< trans(upper);
+ dlog << LINFO << "starting: "<< trans(starting_point);
+
+ x = starting_point;
+ double val = find_min_box_constrained(
+ search_strategy,
+ objective_delta_stop_strategy(1e-16, 500),
+ brown, brown_derivative, x,
+ lower,
+ upper
+ );
+
+ DLIB_TEST(std::abs(val - brown(x)) < 1e-14);
+ dlog << LINFO << "brown solution:\n" << x;
+ return unconstrained_gradient_magnitude(brown_derivative, x, lower, upper);
+ }
+
+ template <typename search_strategy_type>
+ void test_box_constrained_optimizers(search_strategy_type search_strategy)
+ {
+ dlib::rand rnd;
+ running_stats<double> rs;
+
+ dlog << LINFO << "test find_min_box_constrained() on rosen";
+ for (int i = 0; i < 10000; ++i)
+ rs.add(test_bound_solver_rosen(rnd, search_strategy));
+ dlog << LINFO << "mean rosen gradient: " << rs.mean();
+ dlog << LINFO << "max rosen gradient: " << rs.max();
+ DLIB_TEST(rs.mean() < 1e-12);
+ DLIB_TEST(rs.max() < 1e-9);
+
+ dlog << LINFO << "test find_min_box_constrained() on brown";
+ rs.clear();
+ for (int i = 0; i < 1000; ++i)
+ rs.add(test_bound_solver_brown(rnd, search_strategy));
+ dlog << LINFO << "mean brown gradient: " << rs.mean();
+ dlog << LINFO << "max brown gradient: " << rs.max();
+ dlog << LINFO << "min brown gradient: " << rs.min();
+ DLIB_TEST(rs.mean() < 4e-5);
+ DLIB_TEST_MSG(rs.max() < 3e-2, rs.max());
+ DLIB_TEST(rs.min() < 1e-10);
+
+ dlog << LINFO << "test find_max_box_constrained() on neg_rosen";
+ rs.clear();
+ for (int i = 0; i < 1000; ++i)
+ rs.add(test_bound_solver_neg_rosen(rnd, search_strategy));
+ dlog << LINFO << "mean neg_rosen gradient: " << rs.mean();
+ dlog << LINFO << "max neg_rosen gradient: " << rs.max();
+ DLIB_TEST(rs.mean() < 1e-12);
+ DLIB_TEST(rs.max() < 1e-9);
+
+ }
+
+ void test_poly_min_extract_2nd()
+ {
+ double off;
+
+ off = 0.0; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 0.1; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 0.2; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 0.3; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 0.4; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 0.5; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 0.6; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 0.8; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 0.9; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ off = 1.0; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
+ }
+
+ void test_solve_trust_region_subproblem_bounded()
+ {
+ print_spinner();
+ matrix<double> H(2,2);
+ H = 1, 0,
+ 0, 1;
+ matrix<double,0,1> g, lower, upper, p, true_p;
+ g = {0, 0};
+
+ double radius = 0.5;
+ lower = {0.5, 0};
+ upper = {10, 10};
+
+
+ solve_trust_region_subproblem_bounded(H,g, radius, p, 0.001, 500, lower, upper);
+ true_p = { 0.5, 0};
+ DLIB_TEST_MSG(length(p-true_p) < 1e-12, p);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class optimization_tester : public tester
+ {
+ public:
+ optimization_tester (
+ ) :
+ tester ("test_optimization",
+ "Runs tests on the optimization component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "test_box_constrained_optimizers(bfgs_search_strategy())";
+ test_box_constrained_optimizers(bfgs_search_strategy());
+ dlog << LINFO << "test_box_constrained_optimizers(lbfgs_search_strategy(5))";
+ test_box_constrained_optimizers(lbfgs_search_strategy(5));
+ test_poly_min_extract_2nd();
+ optimization_test();
+ test_solve_trust_region_subproblem_bounded();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/optimization_test_functions.cpp b/ml/dlib/dlib/test/optimization_test_functions.cpp
new file mode 100644
index 000000000..1cded50ee
--- /dev/null
+++ b/ml/dlib/dlib/test/optimization_test_functions.cpp
@@ -0,0 +1,425 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include "optimization_test_functions.h"
+
+/*
+
+ Most of the code in this file is converted from the set of Fortran 90 routines
+ created by John Burkardt.
+
+ The original Fortran can be found here: http://orion.math.iastate.edu/burkardt/f_src/testopt/testopt.html
+
+*/
+
+
+namespace dlib
+{
+ namespace test_functions
+ {
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,0,1> chebyquad_residuals(const matrix<double,0,1>& x)
+ {
+ matrix<double,0,1> fvec(x.size());
+ const int n = x.size();
+ int i;
+ int j;
+ double t;
+ double t1;
+ double t2;
+ double th;
+ fvec = 0;
+
+ for (j = 1; j <= n; ++j)
+ {
+ t1 = 1.0E+00;
+ t2 = 2.0E+00 * x(j-1) - 1.0E+00;
+ t = 2.0E+00 * t2;
+ for (i = 1; i <= n; ++i)
+ {
+ fvec(i-1) = fvec(i-1) + t2;
+ th = t * t2 - t1;
+ t1 = t2;
+ t2 = th;
+ }
+ }
+
+ for (i = 1; i <= n; ++i)
+ {
+ fvec(i-1) = fvec(i-1) / (double) ( n );
+ if ( ( i%2 ) == 0 )
+ fvec(i-1) = fvec(i-1) + 1.0E+00 / ( (double)i*i - 1.0E+00 );
+ }
+
+ return fvec;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ double chebyquad_residual(int i, const matrix<double,0,1>& x)
+ {
+ return chebyquad_residuals(x)(i);
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ int& chebyquad_calls()
+ {
+ static int count = 0;
+ return count;
+ }
+
+ double chebyquad(const matrix<double,0,1>& x )
+ {
+ chebyquad_calls()++;
+ return sum(squared(chebyquad_residuals(x)));
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,0,1> chebyquad_derivative (const matrix<double,0,1>& x)
+ {
+ const int n = x.size();
+ matrix<double,0,1> fvec = chebyquad_residuals(x);
+ matrix<double,0,1> g(n);
+ int i;
+ int j;
+ double s1;
+ double s2;
+ double t;
+ double t1;
+ double t2;
+ double th;
+
+ for (j = 1; j <= n; ++j)
+ {
+ g(j-1) = 0.0E+00;
+ t1 = 1.0E+00;
+ t2 = 2.0E+00 * x(j-1) - 1.0E+00;
+ t = 2.0E+00 * t2;
+ s1 = 0.0E+00;
+ s2 = 2.0E+00;
+ for (i = 1; i <= n; ++i)
+ {
+ g(j-1) = g(j-1) + fvec(i-1) * s2;
+ th = 4.0E+00 * t2 + t * s2 - s1;
+ s1 = s2;
+ s2 = th;
+ th = t * t2 - t1;
+ t1 = t2;
+ t2 = th;
+ }
+ }
+
+ g = 2.0E+00 * g / (double) ( n );
+
+ return g;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,0,1> chebyquad_start (int n)
+ {
+ int i;
+ matrix<double,0,1> x(n);
+
+ for (i = 1; i <= n; ++i)
+ x(i-1) = double ( i ) / double ( n + 1 );
+
+ return x;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,0,1> chebyquad_solution (int n)
+ {
+ matrix<double,0,1> x(n);
+
+ x = 0;
+ switch (n)
+ {
+ case 2:
+ x = 0.2113249E+00, 0.7886751E+00;
+ break;
+ case 4:
+ x = 0.1026728E+00, 0.4062037E+00, 0.5937963E+00, 0.8973272E+00;
+ break;
+ case 6:
+ x = 0.066877E+00, 0.288741E+00, 0.366682E+00, 0.633318E+00, 0.711259E+00, 0.933123E+00;
+ break;
+ case 8:
+ x = 0.043153E+00, 0.193091E+00, 0.266329E+00, 0.500000E+00, 0.500000E+00, 0.733671E+00, 0.806910E+00, 0.956847E+00;
+ break;
+ default:
+ std::ostringstream sout;
+ sout << "don't know chebyquad solution for n = " << n;
+ throw dlib::error(sout.str());
+ break;
+ }
+
+ return x;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double> chebyquad_hessian(const matrix<double,0,1>& x)
+ {
+ const int lda = x.size();
+ const int n = x.size();
+ double d1;
+ double d2;
+ matrix<double,0,1> fvec = chebyquad_residuals(x);
+ matrix<double,0,1> gvec(n);
+ matrix<double> h(lda,n);
+ int i;
+ int j;
+ int k;
+ double p1;
+ double p2;
+ double s1;
+ double s2;
+ double ss1;
+ double ss2;
+ double t;
+ double t1;
+ double t2;
+ double th;
+ double tt;
+ double tth;
+ double tt1;
+ double tt2;
+ h = 0;
+
+ d1 = 1.0E+00 / double ( n );
+ d2 = 2.0E+00 * d1;
+
+ for (j = 1; j <= n; ++j)
+ {
+
+ h(j-1,j-1) = 4.0E+00 * d1;
+ t1 = 1.0E+00;
+ t2 = 2.0E+00 * x(j-1) - 1.0E+00;
+ t = 2.0E+00 * t2;
+ s1 = 0.0E+00;
+ s2 = 2.0E+00;
+ p1 = 0.0E+00;
+ p2 = 0.0E+00;
+ gvec(0) = s2;
+
+ for (i = 2; i <= n; ++i)
+ {
+ th = 4.0E+00 * t2 + t * s2 - s1;
+ s1 = s2;
+ s2 = th;
+ th = t * t2 - t1;
+ t1 = t2;
+ t2 = th;
+ th = 8.0E+00 * s1 + t * p2 - p1;
+ p1 = p2;
+ p2 = th;
+ gvec(i-1) = s2;
+ h(j-1,j-1) = h(j-1,j-1) + fvec(i-1) * th + d1 * s2*s2;
+ }
+
+ h(j-1,j-1) = d2 * h(j-1,j-1);
+
+ for (k = 1; k <= j-1; ++k)
+ {
+
+ h(j-1,k-1) = 0.0;
+ tt1 = 1.0E+00;
+ tt2 = 2.0E+00 * x(k-1) - 1.0E+00;
+ tt = 2.0E+00 * tt2;
+ ss1 = 0.0E+00;
+ ss2 = 2.0E+00;
+
+ for (i = 1; i <= n; ++i)
+ {
+ h(j-1,k-1) = h(j-1,k-1) + ss2 * gvec(i-1);
+ tth = 4.0E+00 * tt2 + tt * ss2 - ss1;
+ ss1 = ss2;
+ ss2 = tth;
+ tth = tt * tt2 - tt1;
+ tt1 = tt2;
+ tt2 = tth;
+ }
+
+ h(j-1,k-1) = d2 * d1 * h(j-1,k-1);
+
+ }
+
+ }
+
+ h = make_symmetric(h);
+ return h;
+ }
+
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+
+ double brown_residual (int i, const matrix<double,4,1>& x)
+ /*!
+ requires
+ - 1 <= i <= 20
+ ensures
+ - returns the ith brown residual
+ !*/
+ {
+ double c;
+ double f;
+ double f1;
+ double f2;
+
+ f = 0.0E+00;
+
+
+ c = double ( i ) / 5.0E+00;
+ f1 = x(0) + c * x(1) - std::exp ( c );
+ f2 = x(2) + std::sin ( c ) * x(3) - std::cos ( c );
+
+ f = f1*f1 + f2*f2;
+
+ return f;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ double brown ( const matrix<double,4,1>& x)
+ {
+ double f;
+ int i;
+
+ f = 0;
+
+ for (i = 1; i <= 20; ++i)
+ {
+ f += std::pow(brown_residual(i, x), 2);
+ }
+
+ return f;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,4,1> brown_derivative ( const matrix<double,4,1>& x)
+ {
+ double c;
+ double df1dx1;
+ double df1dx2;
+ double df2dx3;
+ double df2dx4;
+ double f1;
+ double f2;
+ matrix<double,4,1> g;
+ int i;
+
+ g = 0;
+
+ for (i = 1; i <= 20; ++i)
+ {
+
+ c = double ( i ) / 5.0E+00;
+
+ f1 = x(0) + c * x(1) - std::exp ( c );
+ f2 = x(2) + std::sin ( c ) * x(3) - std::cos ( c );
+
+ df1dx1 = 1.0E+00;
+ df1dx2 = c;
+ df2dx3 = 1.0E+00;
+ df2dx4 = std::sin ( c );
+
+ using std::pow;
+ g(0) = g(0) + 4.0E+00 * ( pow(f1,3) * df1dx1 + f1 * pow(f2,2) * df1dx1 );
+ g(1) = g(1) + 4.0E+00 * ( pow(f1,3) * df1dx2 + f1 * pow(f2,2) * df1dx2 );
+ g(2) = g(2) + 4.0E+00 * ( pow(f1,2) * f2 * df2dx3 + pow(f2,3) * df2dx3 );
+ g(3) = g(3) + 4.0E+00 * ( pow(f1,2) * f2 * df2dx4 + pow(f2,3) * df2dx4 );
+
+ }
+
+ return g;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,4,4> brown_hessian ( const matrix<double,4,1>& x)
+ {
+ double c;
+ double df1dx1;
+ double df1dx2;
+ double df2dx3;
+ double df2dx4;
+ double f1;
+ double f2;
+ matrix<double,4,4> h;
+ int i;
+
+ h = 0;
+
+ for (i = 1; i <= 20; ++i)
+ {
+
+ c = double ( i ) / 5.0E+00;
+
+ f1 = x(0) + c * x(1) - std::exp ( c );
+ f2 = x(2) + std::sin ( c ) * x(3) - std::cos ( c );
+
+ df1dx1 = 1.0E+00;
+ df1dx2 = c;
+ df2dx3 = 1.0E+00;
+ df2dx4 = std::sin ( c );
+
+ using std::pow;
+ h(0,0) = h(0,0) + 12.0E+00 * pow(f1,2) * df1dx1 * df1dx1 + 4.0E+00 * pow(f2,2) * df1dx1 * df1dx1;
+ h(0,1) = h(0,1) + 12.0E+00 * pow(f1,2) * df1dx1 * df1dx2 + 4.0E+00 * pow(f2,2) * df1dx1 * df1dx2;
+ h(0,2) = h(0,2) + 8.0E+00 * f1 * f2 * df1dx1 * df2dx3;
+ h(0,3) = h(0,3) + 8.0E+00 * f1 * f2 * df1dx1 * df2dx4;
+
+ h(1,0) = h(1,0) + 12.0E+00 * pow(f1,2) * df1dx2 * df1dx1 + 4.0E+00 * pow(f2,2) * df1dx2 * df1dx1;
+ h(1,1) = h(1,1) + 12.0E+00 * pow(f1,2) * df1dx2 * df1dx2 + 4.0E+00 * pow(f2,2) * df1dx2 * df1dx2;
+ h(1,2) = h(1,2) + 8.0E+00 * f1 * f2 * df1dx2 * df2dx3;
+ h(1,3) = h(1,3) + 8.0E+00 * f1 * f2 * df1dx2 * df2dx4;
+
+ h(2,0) = h(2,0) + 8.0E+00 * f1 * f2 * df2dx3 * df1dx1;
+ h(2,1) = h(2,1) + 8.0E+00 * f1 * f2 * df2dx3 * df1dx2;
+ h(2,2) = h(2,2) + 4.0E+00 * pow(f1,2) * df2dx3 * df2dx3 + 12.0E+00 * pow(f2,2) * df2dx3 * df2dx3;
+ h(2,3) = h(2,3) + 4.0E+00 * pow(f1,2) * df2dx4 * df2dx3 + 12.0E+00 * pow(f2,2) * df2dx3 * df2dx4;
+
+ h(3,0) = h(3,0) + 8.0E+00 * f1 * f2 * df2dx4 * df1dx1;
+ h(3,1) = h(3,1) + 8.0E+00 * f1 * f2 * df2dx4 * df1dx2;
+ h(3,2) = h(3,2) + 4.0E+00 * pow(f1,2) * df2dx3 * df2dx4 + 12.0E+00 * pow(f2,2) * df2dx4 * df2dx3;
+ h(3,3) = h(3,3) + 4.0E+00 * pow(f1,2) * df2dx4 * df2dx4 + 12.0E+00 * pow(f2,2) * df2dx4 * df2dx4;
+
+ }
+
+ return make_symmetric(h);
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,4,1> brown_start ()
+ {
+ matrix<double,4,1> x;
+ x = 25.0E+00, 5.0E+00, -5.0E+00, -1.0E+00;
+ return x;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,4,1> brown_solution ()
+ {
+ matrix<double,4,1> x;
+ // solution from original documentation.
+ //x = -11.5844E+00, 13.1999E+00, -0.406200E+00, 0.240998E+00;
+ x = -11.594439905669450042, 13.203630051593080452, -0.40343948856573402795, 0.23677877338218666914;
+ return x;
+ }
+
+ // ----------------------------------------------------------------------------------------
+
+ }
+}
+
+
diff --git a/ml/dlib/dlib/test/optimization_test_functions.h b/ml/dlib/dlib/test/optimization_test_functions.h
new file mode 100644
index 000000000..a20523eae
--- /dev/null
+++ b/ml/dlib/dlib/test/optimization_test_functions.h
@@ -0,0 +1,310 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_OPTIMIZATION_TEST_FUNCTiONS_H_h_
+#define DLIB_OPTIMIZATION_TEST_FUNCTiONS_H_h_
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <cmath>
+
+/*
+
+ Most of the code in this file is converted from the set of Fortran 90 routines
+ created by John Burkardt.
+
+ The original Fortran can be found here: http://orion.math.iastate.edu/burkardt/f_src/testopt/testopt.html
+
+*/
+
+// GCC 4.8 gives false alarms about some variables being uninitialized. Disable these
+// false warnings.
+#if ( defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8)
+ #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
+
+namespace dlib
+{
+ namespace test_functions
+ {
+
+ // ----------------------------------------------------------------------------------------
+
+ matrix<double,0,1> chebyquad_residuals(const matrix<double,0,1>& x);
+
+ double chebyquad_residual(int i, const matrix<double,0,1>& x);
+
+ int& chebyquad_calls();
+
+ double chebyquad(const matrix<double,0,1>& x );
+
+ matrix<double,0,1> chebyquad_derivative (const matrix<double,0,1>& x);
+
+ matrix<double,0,1> chebyquad_start (int n);
+
+ matrix<double,0,1> chebyquad_solution (int n);
+
+ matrix<double> chebyquad_hessian(const matrix<double,0,1>& x);
+
+ // ----------------------------------------------------------------------------------------
+
+ class chebyquad_function_model
+ {
+ public:
+
+ // Define the type used to represent column vectors
+ typedef matrix<double,0,1> column_vector;
+ // Define the type used to represent the hessian matrix
+ typedef matrix<double> general_matrix;
+
+ double operator() (
+ const column_vector& x
+ ) const
+ {
+ return chebyquad(x);
+ }
+
+ void get_derivative_and_hessian (
+ const column_vector& x,
+ column_vector& d,
+ general_matrix& h
+ ) const
+ {
+ d = chebyquad_derivative(x);
+ h = chebyquad_hessian(x);
+ }
+ };
+
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+
+ double brown_residual (int i, const matrix<double,4,1>& x);
+ /*!
+ requires
+ - 1 <= i <= 20
+ ensures
+ - returns the ith brown residual
+ !*/
+
+ double brown ( const matrix<double,4,1>& x);
+
+ matrix<double,4,1> brown_derivative ( const matrix<double,4,1>& x);
+
+ matrix<double,4,4> brown_hessian ( const matrix<double,4,1>& x);
+
+ matrix<double,4,1> brown_start ();
+
+ matrix<double,4,1> brown_solution ();
+
+ class brown_function_model
+ {
+ public:
+
+ // Define the type used to represent column vectors
+ typedef matrix<double,4,1> column_vector;
+ // Define the type used to represent the hessian matrix
+ typedef matrix<double> general_matrix;
+
+ double operator() (
+ const column_vector& x
+ ) const
+ {
+ return brown(x);
+ }
+
+ void get_derivative_and_hessian (
+ const column_vector& x,
+ column_vector& d,
+ general_matrix& h
+ ) const
+ {
+ d = brown_derivative(x);
+ h = brown_hessian(x);
+ }
+ };
+
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ matrix<T,2,1> rosen_big_start()
+ {
+ matrix<T,2,1> x;
+ x = -1.2, -1;
+ return x;
+ }
+
+ // This is a variation on the Rosenbrock test function but with large residuals. The
+ // minimum is at 1, 1 and the objective value is 1.
+ template <typename T>
+ T rosen_big_residual (int i, const matrix<T,2,1>& m)
+ {
+ using std::pow;
+ const T x = m(0);
+ const T y = m(1);
+
+ if (i == 1)
+ {
+ return 100*pow(y - x*x,2)+1.0;
+ }
+ else
+ {
+ return pow(1 - x,2) + 1.0;
+ }
+ }
+
+ template <typename T>
+ T rosen_big ( const matrix<T,2,1>& m)
+ {
+ using std::pow;
+ return 0.5*(pow(rosen_big_residual(1,m),2) + pow(rosen_big_residual(2,m),2));
+ }
+
+ template <typename T>
+ matrix<T,2,1> rosen_big_solution ()
+ {
+ matrix<T,2,1> x;
+ // solution from original documentation.
+ x = 1,1;
+ return x;
+ }
+
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ matrix<T,2,1> rosen_start()
+ {
+ matrix<T,2,1> x;
+ x = -1.2, -1;
+ return x;
+ }
+
+ template <typename T>
+ T rosen ( const matrix<T,2,1>& m)
+ {
+ const T x = m(0);
+ const T y = m(1);
+
+ using std::pow;
+ // compute Rosenbrock's function and return the result
+ return 100.0*pow(y - x*x,2) + pow(1 - x,2);
+ }
+
+ template <typename T>
+ T rosen_residual (int i, const matrix<T,2,1>& m)
+ {
+ const T x = m(0);
+ const T y = m(1);
+
+
+ if (i == 1)
+ {
+ return 10*(y - x*x);
+ }
+ else
+ {
+ return 1 - x;
+ }
+ }
+
+ template <typename T>
+ matrix<T,2,1> rosen_residual_derivative (int i, const matrix<T,2,1>& m)
+ {
+ const T x = m(0);
+
+ matrix<T,2,1> d;
+
+ if (i == 1)
+ {
+ d = -20*x, 10;
+ }
+ else
+ {
+ d = -1, 0;
+ }
+ return d;
+ }
+
+ template <typename T>
+ const matrix<T,2,1> rosen_derivative ( const matrix<T,2,1>& m)
+ {
+ const T x = m(0);
+ const T y = m(1);
+
+ // make us a column vector of length 2
+ matrix<T,2,1> res(2);
+
+ // now compute the gradient vector
+ res(0) = -400*x*(y-x*x) - 2*(1-x); // derivative of rosen() with respect to x
+ res(1) = 200*(y-x*x); // derivative of rosen() with respect to y
+ return res;
+ }
+
+ template <typename T>
+ const matrix<T,2,2> rosen_hessian ( const matrix<T,2,1>& m)
+ {
+ const T x = m(0);
+ const T y = m(1);
+
+ // make us a column vector of length 2
+ matrix<T,2,2> res;
+
+ // now compute the gradient vector
+ res(0,0) = -400*y + 3*400*x*x + 2;
+ res(1,1) = 200;
+
+ res(0,1) = -400*x;
+ res(1,0) = -400*x;
+ return res;
+ }
+
+ template <typename T>
+ matrix<T,2,1> rosen_solution ()
+ {
+ matrix<T,2,1> x;
+ // solution from original documentation.
+ x = 1,1;
+ return x;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ template <typename T>
+ struct rosen_function_model
+ {
+ typedef matrix<T,2,1> column_vector;
+ typedef matrix<T,2,2> general_matrix;
+
+ T operator() ( column_vector x) const
+ {
+ return static_cast<T>(rosen(x));
+ }
+
+ void get_derivative_and_hessian (
+ const column_vector& x,
+ column_vector& d,
+ general_matrix& h
+ ) const
+ {
+ d = rosen_derivative(x);
+ h = rosen_hessian(x);
+ }
+
+ };
+
+ // ----------------------------------------------------------------------------------------
+
+ }
+}
+
+#endif // DLIB_OPTIMIZATION_TEST_FUNCTiONS_H_h_
+
+
+
diff --git a/ml/dlib/dlib/test/parallel_for.cpp b/ml/dlib/dlib/test/parallel_for.cpp
new file mode 100644
index 000000000..5bee40955
--- /dev/null
+++ b/ml/dlib/dlib/test/parallel_for.cpp
@@ -0,0 +1,334 @@
+// Copyright (C) 2013 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/threads.h>
+#include <vector>
+#include <sstream>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.parallel_for");
+
+ class assign_element
+ {
+ public:
+
+ assign_element(
+ std::vector<int>& vect_
+ ) : vect(vect_){}
+
+ std::vector<int>& vect;
+
+ void go (long i )
+ {
+ DLIB_TEST( 0 <= i && i < (long)vect.size());
+ vect[i] = i;
+ }
+
+ void operator() (long i ) const
+ {
+ DLIB_TEST( 0 <= i && i < (long)vect.size());
+ vect[i] = i;
+ }
+
+ };
+
+ void test_parallel_for(long start)
+ {
+ std::vector<int> vect(200,0);
+
+ parallel_for(4, start, vect.size(), assign_element(vect));
+
+ for (long i = 0; i < start; ++i)
+ {
+ DLIB_TEST(vect[i] == 0);
+ }
+ for (long i = start; i < (long)vect.size(); ++i)
+ {
+ DLIB_TEST(vect[i] == i);
+ }
+ }
+
+ void test_parallel_for2(long start)
+ {
+ std::vector<int> vect(200,0);
+
+ assign_element temp(vect);
+ parallel_for(4, start, vect.size(), temp, &assign_element::go);
+
+ for (long i = 0; i < start; ++i)
+ {
+ DLIB_TEST(vect[i] == 0);
+ }
+ for (long i = start; i < (long)vect.size(); ++i)
+ {
+ DLIB_TEST(vect[i] == i);
+ }
+ }
+
+ struct parfor_test_helper
+ {
+ mutable std::vector<int> test;
+
+ parfor_test_helper() : test(400,100000)
+ {
+ }
+
+ void go(long begin, long end)
+ {
+ for (long i = begin; i < end; ++i)
+ test[i] = i;
+ }
+
+ void operator()(long begin, long end) const
+ {
+ for (long i = begin; i < end; ++i)
+ test[i] = i;
+ }
+
+ void go2(long i)
+ {
+ test[i] = i;
+ }
+
+ };
+
+ struct parfor_test_helper2
+ {
+ mutable std::vector<int> test;
+
+ parfor_test_helper2() : test(400,100000)
+ {
+ }
+
+ void operator()(long i) const
+ {
+ test[i] = i;
+ }
+
+ };
+
+ void test_parallel_for_additional()
+ {
+ {
+ parfor_test_helper helper;
+ parallel_for(4, 0, helper.test.size(), helper, &parfor_test_helper::go2);
+
+ for (unsigned long i = 0; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for(4, 10, helper.test.size(), helper, &parfor_test_helper::go2);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]);
+ }
+ for (unsigned long i = 10; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_blocked(4, 0, helper.test.size(), helper, &parfor_test_helper::go);
+
+ for (unsigned long i = 0; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_blocked(4, 10, helper.test.size(), helper, &parfor_test_helper::go);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]);
+ }
+ for (unsigned long i = 10; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_blocked(4, 0, helper.test.size(), helper);
+
+ for (unsigned long i = 0; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_blocked(4, 10, helper.test.size(), helper);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]);
+ }
+ for (unsigned long i = 10; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper2 helper;
+ parallel_for(4, 0, helper.test.size(), helper);
+
+ for (unsigned long i = 0; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper2 helper;
+ parallel_for(4, 10, helper.test.size(), helper);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]);
+ }
+ for (unsigned long i = 10; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+
+
+
+
+
+
+ {
+ parfor_test_helper helper;
+ parallel_for_verbose(4, 0, helper.test.size(), helper, &parfor_test_helper::go2);
+
+ for (unsigned long i = 0; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_verbose(4, 10, helper.test.size(), helper, &parfor_test_helper::go2);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]);
+ }
+ for (unsigned long i = 10; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_blocked_verbose(4, 0, helper.test.size(), helper, &parfor_test_helper::go);
+
+ for (unsigned long i = 0; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_blocked_verbose(4, 10, helper.test.size(), helper, &parfor_test_helper::go);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]);
+ }
+ for (unsigned long i = 10; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_blocked_verbose(4, 0, helper.test.size(), helper);
+
+ for (unsigned long i = 0; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper helper;
+ parallel_for_blocked_verbose(4, 10, helper.test.size(), helper);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]);
+ }
+ for (unsigned long i = 10; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper2 helper;
+ parallel_for_verbose(4, 0, helper.test.size(), helper);
+
+ for (unsigned long i = 0; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ {
+ parfor_test_helper2 helper;
+ parallel_for_verbose(4, 10, helper.test.size(), helper);
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]);
+ }
+ for (unsigned long i = 10; i < helper.test.size(); ++i)
+ {
+ DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]);
+ }
+ }
+ }
+
+ class test_parallel_for_routines : public tester
+ {
+ public:
+ test_parallel_for_routines (
+ ) :
+ tester (
+ "test_parallel_for", // the command line argument name for this test
+ "Run tests on the parallel_for routines.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+ void perform_test (
+ )
+ {
+ test_parallel_for(0);
+ test_parallel_for(30);
+ test_parallel_for(50);
+ test_parallel_for2(0);
+ test_parallel_for2(30);
+ test_parallel_for2(50);
+
+ test_parallel_for_additional();
+ }
+ };
+
+ test_parallel_for_routines a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/parse.cpp b/ml/dlib/dlib/test/parse.cpp
new file mode 100644
index 000000000..b0ea13b1b
--- /dev/null
+++ b/ml/dlib/dlib/test/parse.cpp
@@ -0,0 +1,233 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <dlib/optimization.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+
+ logger dlog("test.parse");
+
+// ----------------------------------------------------------------------------------------
+
+ const unsigned long DET = 0;
+ const unsigned long N = 1;
+ const unsigned long V = 2;
+ const unsigned long NP = 3;
+ const unsigned long VP = 4;
+ const unsigned long S = 5;
+ const unsigned long B = 6;
+ const unsigned long G = 7;
+ const unsigned long A = 8;
+
+ typedef unsigned long tags;
+
+ template <bool has_glue_term>
+ void user_defined_ruleset (
+ const std::vector<tags>& words,
+ const constituent<tags>& c,
+ std::vector<std::pair<tags,double> >& possible_ids
+ )
+ {
+ DLIB_TEST(c.begin < c.k && c.k < c.end && c.end <= words.size());
+ DLIB_TEST(possible_ids.size() == 0);
+
+ if (c.left_tag == NP && c.right_tag == VP) possible_ids.push_back(make_pair(S,log(0.80)));
+ else if (c.left_tag == DET && c.right_tag == N) possible_ids.push_back(make_pair(NP,log(0.30)));
+ else if (c.left_tag == VP && c.right_tag == A) possible_ids.push_back(make_pair(VP,log(0.30)));
+ else if (c.left_tag == V && c.right_tag == NP)
+ {
+ possible_ids.push_back(make_pair(VP,log(0.20)));
+ possible_ids.push_back(make_pair(B,0.10));
+ }
+ else if (has_glue_term)
+ {
+ possible_ids.push_back(make_pair(G, log(0.01)));
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void dotest1()
+ {
+ print_spinner();
+ dlog << LINFO << "in dotest1()";
+
+ std::vector<std::string> words;
+ std::vector<tags> sequence;
+ for (int i = 0; i < 8; ++i)
+ {
+ sequence.push_back(DET);
+ sequence.push_back(N);
+ sequence.push_back(V);
+ sequence.push_back(DET);
+ sequence.push_back(N);
+ sequence.push_back(A);
+
+ words.push_back("The");
+ words.push_back("flight");
+ words.push_back("includes");
+ words.push_back("a");
+ words.push_back("meal");
+ words.push_back("AWORD");
+ }
+
+ std::vector<parse_tree_element<tags> > parse_tree;
+
+ find_max_parse_cky(sequence, user_defined_ruleset<true>, parse_tree);
+ DLIB_TEST(parse_tree.size() != 0);
+
+
+ std::vector<unsigned long> roots;
+ find_trees_not_rooted_with_tag(parse_tree, G, roots);
+ DLIB_TEST(roots.size() == 8);
+
+ for (unsigned long i = 0; i < roots.size(); ++i)
+ {
+ dlog << LINFO << parse_tree_to_string(parse_tree, words, roots[i]);
+ DLIB_TEST(parse_tree_to_string(parse_tree, words, roots[i]) == "[[The flight] [[includes [a meal]] AWORD]]");
+ dlog << LINFO << parse_tree_to_string_tagged(parse_tree, words, roots[i]);
+ DLIB_TEST(parse_tree_to_string_tagged(parse_tree, words, roots[i]) == "[5 [3 The flight] [4 [4 includes [3 a meal]] AWORD]]");
+ }
+
+
+ words.clear();
+ sequence.clear();
+
+ for (int i = 0; i < 2; ++i)
+ {
+ sequence.push_back(DET);
+ sequence.push_back(N);
+ sequence.push_back(V);
+ sequence.push_back(DET);
+ sequence.push_back(N);
+
+ words.push_back("The");
+ words.push_back("flight");
+ words.push_back("includes");
+ words.push_back("a");
+ words.push_back("meal");
+ }
+
+ find_max_parse_cky(sequence, user_defined_ruleset<true>, parse_tree);
+ DLIB_TEST(parse_tree.size() != 0);
+
+ const std::string str1 = "[[[The flight] [includes [a meal]]] [[The flight] [includes [a meal]]]]";
+ const std::string str2 = "[7 [5 [3 The flight] [4 includes [3 a meal]]] [5 [3 The flight] [4 includes [3 a meal]]]]";
+ dlog << LINFO << parse_tree_to_string(parse_tree, words);
+ DLIB_TEST(parse_tree_to_string(parse_tree, words) == str1);
+ dlog << LINFO << parse_tree_to_string_tagged(parse_tree, words);
+ DLIB_TEST(parse_tree_to_string_tagged(parse_tree, words) == str2);
+
+ const std::string str3 = "[[The flight] [includes [a meal]]] [[The flight] [includes [a meal]]]";
+ const std::string str4 = "[5 [3 The flight] [4 includes [3 a meal]]] [5 [3 The flight] [4 includes [3 a meal]]]";
+ dlog << LINFO << parse_trees_to_string(parse_tree, words, G);
+ DLIB_TEST(parse_trees_to_string(parse_tree, words, G) == str3);
+ dlog << LINFO << parse_trees_to_string_tagged(parse_tree, words, G);
+ DLIB_TEST(parse_trees_to_string_tagged(parse_tree, words, G) == str4);
+
+ sequence.clear();
+ find_max_parse_cky(sequence, user_defined_ruleset<true>, parse_tree);
+ DLIB_TEST(parse_tree.size() == 0);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void dotest2()
+ {
+ print_spinner();
+ dlog << LINFO << "in dotest2()";
+
+ std::vector<std::string> words;
+ std::vector<tags> sequence;
+ for (int i = 0; i < 8; ++i)
+ {
+ sequence.push_back(DET);
+ sequence.push_back(N);
+ sequence.push_back(V);
+ sequence.push_back(DET);
+ sequence.push_back(N);
+
+ words.push_back("The");
+ words.push_back("flight");
+ words.push_back("includes");
+ words.push_back("a");
+ words.push_back("meal");
+ }
+
+ std::vector<parse_tree_element<tags> > parse_tree;
+
+ find_max_parse_cky(sequence, user_defined_ruleset<false>, parse_tree);
+ DLIB_TEST(parse_tree.size() == 0);
+
+
+ std::vector<unsigned long> roots;
+ find_trees_not_rooted_with_tag(parse_tree, G, roots);
+ DLIB_TEST(roots.size() == 0);
+
+
+ words.clear();
+ sequence.clear();
+
+ for (int i = 0; i < 2; ++i)
+ {
+ sequence.push_back(DET);
+ sequence.push_back(N);
+ sequence.push_back(V);
+ sequence.push_back(DET);
+ sequence.push_back(N);
+
+ words.push_back("The");
+ words.push_back("flight");
+ words.push_back("includes");
+ words.push_back("a");
+ words.push_back("meal");
+ }
+
+ find_max_parse_cky(sequence, user_defined_ruleset<false>, parse_tree);
+ DLIB_TEST(parse_tree.size() == 0);
+
+ sequence.clear();
+ find_max_parse_cky(sequence, user_defined_ruleset<false>, parse_tree);
+ DLIB_TEST(parse_tree.size() == 0);
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ class parse_tester : public tester
+ {
+ public:
+ parse_tester (
+ ) :
+ tester ("test_parse",
+ "Runs tests on the parsing tools.")
+ {}
+
+
+ void perform_test (
+ )
+ {
+ dotest1();
+ dotest2();
+ }
+ } a;
+
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/pipe.cpp b/ml/dlib/dlib/test/pipe.cpp
new file mode 100644
index 000000000..d84dd0d44
--- /dev/null
+++ b/ml/dlib/dlib/test/pipe.cpp
@@ -0,0 +1,688 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/misc_api.h>
+#include <dlib/pipe.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.pipe");
+
+ namespace pipe_kernel_test_helpers
+ {
+ const unsigned long proc1_count = 10000;
+ dlib::mutex m;
+ signaler s(m);
+ unsigned long threads_running = 0;
+ bool found_error;
+
+ inline void add_running_thread (
+ )
+ {
+ auto_mutex M(m);
+ ++threads_running;
+ }
+
+ inline void remove_running_thread (
+ )
+ {
+ auto_mutex M(m);
+ --threads_running;
+ s.broadcast();
+ }
+
+ inline void wait_for_threads (
+ )
+ {
+ auto_mutex M(m);
+ while (threads_running > 0)
+ s.wait();
+ }
+
+ template <
+ typename pipe
+ >
+ void threadproc1 (
+ void* param
+ )
+ {
+ add_running_thread();
+ pipe& p = *static_cast<pipe*>(param);
+ try
+ {
+
+ int last = -1;
+ for (unsigned long i = 0; i < proc1_count; ++i)
+ {
+ int cur=0;
+ DLIB_TEST(p.dequeue(cur) == true);
+ DLIB_TEST(last + 1 == cur);
+ last = cur;
+ }
+ DLIB_TEST(p.size() == 0);
+ }
+ catch(exception& e)
+ {
+ auto_mutex M(m);
+ found_error = true;
+ cout << "\n\nERRORS FOUND" << endl;
+ cout << e.what() << endl;
+ dlog << LWARN << "ERRORS FOUND";
+ dlog << LWARN << e.what();
+ p.disable();
+ }
+
+ remove_running_thread();
+ }
+
+
+ template <
+ typename pipe
+ >
+ void threadproc2 (
+ void* param
+ )
+ {
+ add_running_thread();
+ pipe& p = *static_cast<pipe*>(param);
+ try
+ {
+
+ int last = -1;
+ int cur;
+ while (p.dequeue(cur))
+ {
+ DLIB_TEST(last < cur);
+ last = cur;
+ }
+ auto_mutex M(m);
+ }
+ catch(exception& e)
+ {
+ auto_mutex M(m);
+ found_error = true;
+ cout << "\n\nERRORS FOUND" << endl;
+ cout << e.what() << endl;
+ dlog << LWARN << "ERRORS FOUND";
+ dlog << LWARN << e.what();
+ p.disable();
+ }
+ remove_running_thread();
+ }
+
+
+
+ template <
+ typename pipe
+ >
+ void threadproc3 (
+ void* param
+ )
+ {
+ add_running_thread();
+ pipe& p = *static_cast<pipe*>(param);
+ try
+ {
+
+ int last = -1;
+ int cur;
+ while (p.dequeue_or_timeout(cur,100000))
+ {
+ DLIB_TEST(last < cur);
+ last = cur;
+ }
+ auto_mutex M(m);
+ }
+ catch(exception& e)
+ {
+ auto_mutex M(m);
+ found_error = true;
+ cout << "\n\nERRORS FOUND" << endl;
+ cout << e.what() << endl;
+ dlog << LWARN << "ERRORS FOUND";
+ dlog << LWARN << e.what();
+ p.disable();
+ }
+ remove_running_thread();
+ }
+
+
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ template<typename in_type, typename out_type>
+ class PipelineProcessor : private dlib::threaded_object
+ {
+ public:
+ PipelineProcessor(
+ dlib::pipe<in_type> & in,
+ dlib::pipe<out_type> & out) :
+ InPipe(in),
+ OutPipe(out),
+ InMsg(),
+ OutMsg() {
+ start();
+ }
+
+ ~PipelineProcessor() {
+ // signal the thread to stop
+ stop();
+ wait();
+ }
+
+ private:
+ dlib::pipe<in_type> & InPipe;
+ dlib::pipe<out_type> & OutPipe;
+
+ in_type InMsg;
+ out_type OutMsg;
+
+ void thread()
+ {
+ while (!should_stop()) {
+ if(InPipe.dequeue_or_timeout(InMsg, 100))
+ {
+ // if function signals ready to send OutMsg
+ while (!OutPipe.enqueue_or_timeout(OutMsg, 100))
+ {
+ // try to send until should stop
+ if (should_stop())
+ {
+ return;
+ }
+ }
+ }
+ }
+ };
+ };
+
+
+ void do_zero_size_test_with_timeouts()
+ {
+ dlog << LINFO << "in do_zero_size_test_with_timeouts()";
+ // make sure we can get though this without deadlocking
+ for (int k = 0; k < 10; ++k)
+ {
+ dlib::pipe<int> in_pipe(10);
+ dlib::pipe<float> out_pipe(0);
+ {
+ PipelineProcessor<int, float> pp(in_pipe, out_pipe);
+
+ int in = 1;
+ in_pipe.enqueue(in);
+ in = 2;
+ in_pipe.enqueue(in);
+ in = 3;
+ in_pipe.enqueue(in);
+ // sleep to make sure thread enqueued
+ dlib::sleep(100);
+
+ float out = 1.0f;
+ out_pipe.dequeue(out);
+ dlib::sleep(100);
+ }
+ print_spinner();
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename pipe
+ >
+ void pipe_kernel_test (
+ )
+ /*!
+ requires
+ - pipe is an implementation of pipe/pipe_kernel_abstract.h and
+ is instantiated with int
+ ensures
+ - runs tests on pipe for compliance with the specs
+ !*/
+ {
+ using namespace pipe_kernel_test_helpers;
+ found_error = false;
+
+
+ print_spinner();
+ pipe test(10), test2(100);
+ pipe test_0(0), test2_0(0);
+ pipe test_1(1), test2_1(1);
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test_0.size() == 0);
+ DLIB_TEST(test2_0.size() == 0);
+ DLIB_TEST(test_1.size() == 0);
+ DLIB_TEST(test2_1.size() == 0);
+
+ DLIB_TEST(test.is_enqueue_enabled() == true);
+ DLIB_TEST(test.is_dequeue_enabled() == true);
+ DLIB_TEST(test.is_enabled() == true);
+
+ test.empty();
+ test2.empty();
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test2.size() == 0);
+
+ test_0.empty();
+ test2_0.empty();
+ DLIB_TEST(test_0.size() == 0);
+ DLIB_TEST(test2_0.size() == 0);
+
+ test_1.empty();
+ test2_1.empty();
+ DLIB_TEST(test_1.size() == 0);
+ DLIB_TEST(test2_1.size() == 0);
+
+
+
+ int a;
+ a = 3;
+ test.enqueue(a);
+ DLIB_TEST(test.size() == 1);
+ a = 5;
+ test.enqueue(a);
+ DLIB_TEST(test.size() == 2);
+
+ a = 0;
+ test.dequeue(a);
+ DLIB_TEST(a == 3);
+ DLIB_TEST(test.size() == 1);
+
+ a = 0;
+ test.dequeue(a);
+ DLIB_TEST(a == 5);
+ DLIB_TEST(test.size() == 0);
+
+
+ print_spinner();
+ {
+ dlog << LINFO << "starting normal length pipe tests";
+ create_new_thread(&threadproc1<pipe>,&test);
+ create_new_thread(&threadproc2<pipe>,&test2);
+ create_new_thread(&threadproc2<pipe>,&test2);
+ create_new_thread(&threadproc2<pipe>,&test2);
+
+ for (unsigned long i = 0; i < proc1_count; ++i)
+ {
+ a = i;
+ test.enqueue(a);
+ }
+ DLIB_TEST(test.is_enqueue_enabled() == true);
+ test.disable_enqueue();
+ DLIB_TEST(test.is_enqueue_enabled() == false);
+ for (unsigned long i = 0; i < proc1_count; ++i)
+ {
+ a = i;
+ test.enqueue(a);
+ }
+
+ for (unsigned long i = 0; i < 100000; ++i)
+ {
+ a = i;
+ if (i%2 == 0)
+ test2.enqueue(a);
+ else
+ test2.enqueue_or_timeout(a,100000);
+ }
+
+ test2.wait_for_num_blocked_dequeues(3);
+ DLIB_TEST(test2.size() == 0);
+ test2.disable();
+
+ wait_for_threads();
+ DLIB_TEST(test2.size() == 0);
+
+ test2.enable();
+
+ print_spinner();
+
+ create_new_thread(&threadproc3<pipe>,&test2);
+ create_new_thread(&threadproc3<pipe>,&test2);
+
+
+ for (unsigned long i = 0; i < 100000; ++i)
+ {
+ a = i;
+ if (i%2 == 0)
+ test2.enqueue(a);
+ else
+ test2.enqueue_or_timeout(a,100000);
+ }
+
+ test2.wait_for_num_blocked_dequeues(2);
+ DLIB_TEST(test2.size() == 0);
+ test2.disable();
+
+ wait_for_threads();
+ DLIB_TEST(test2.size() == 0);
+
+ }
+
+
+ print_spinner();
+ {
+ dlog << LINFO << "starting 0 length pipe tests";
+ create_new_thread(&threadproc1<pipe>,&test_0);
+ create_new_thread(&threadproc2<pipe>,&test2_0);
+ create_new_thread(&threadproc2<pipe>,&test2_0);
+ create_new_thread(&threadproc2<pipe>,&test2_0);
+ dlog << LTRACE << "0: 1";
+
+ for (unsigned long i = 0; i < proc1_count; ++i)
+ {
+ a = i;
+ test_0.enqueue(a);
+ }
+
+ dlog << LTRACE << "0: 2";
+ DLIB_TEST(test_0.is_enqueue_enabled() == true);
+ test_0.disable_enqueue();
+ DLIB_TEST(test_0.is_enqueue_enabled() == false);
+ for (unsigned long i = 0; i < proc1_count; ++i)
+ {
+ a = i;
+ test_0.enqueue(a);
+ }
+
+ dlog << LTRACE << "0: 3";
+ for (unsigned long i = 0; i < 100000; ++i)
+ {
+ a = i;
+ if (i%2 == 0)
+ test2_0.enqueue(a);
+ else
+ test2_0.enqueue_or_timeout(a,100000);
+ }
+
+ print_spinner();
+ dlog << LTRACE << "0: 4";
+ test2_0.wait_for_num_blocked_dequeues(3);
+ DLIB_TEST(test2_0.size() == 0);
+ test2_0.disable();
+
+ wait_for_threads();
+ DLIB_TEST(test2_0.size() == 0);
+
+ dlog << LTRACE << "0: 5";
+ test2_0.enable();
+
+
+ create_new_thread(&threadproc3<pipe>,&test2_0);
+ create_new_thread(&threadproc3<pipe>,&test2_0);
+
+
+ for (unsigned long i = 0; i < 20000; ++i)
+ {
+ if ((i%100) == 0)
+ print_spinner();
+
+ a = i;
+ if (i%2 == 0)
+ test2_0.enqueue(a);
+ else
+ test2_0.enqueue_or_timeout(a,100000);
+ }
+
+ dlog << LTRACE << "0: 6";
+ test2_0.wait_for_num_blocked_dequeues(2);
+ DLIB_TEST(test2_0.size() == 0);
+ test2_0.disable();
+
+ wait_for_threads();
+ DLIB_TEST(test2_0.size() == 0);
+
+ dlog << LTRACE << "0: 7";
+ }
+
+ print_spinner();
+ {
+ dlog << LINFO << "starting 1 length pipe tests";
+ create_new_thread(&threadproc1<pipe>,&test_1);
+ create_new_thread(&threadproc2<pipe>,&test2_1);
+ create_new_thread(&threadproc2<pipe>,&test2_1);
+ create_new_thread(&threadproc2<pipe>,&test2_1);
+
+ for (unsigned long i = 0; i < proc1_count; ++i)
+ {
+ a = i;
+ test_1.enqueue(a);
+ }
+ DLIB_TEST(test_1.is_enqueue_enabled() == true);
+ test_1.disable_enqueue();
+ DLIB_TEST(test_1.is_enqueue_enabled() == false);
+ for (unsigned long i = 0; i < proc1_count; ++i)
+ {
+ a = i;
+ test_1.enqueue(a);
+ }
+ print_spinner();
+
+ for (unsigned long i = 0; i < 100000; ++i)
+ {
+ a = i;
+ if (i%2 == 0)
+ test2_1.enqueue(a);
+ else
+ test2_1.enqueue_or_timeout(a,100000);
+ }
+
+ test2_1.wait_for_num_blocked_dequeues(3);
+ DLIB_TEST(test2_1.size() == 0);
+ test2_1.disable();
+
+ wait_for_threads();
+ DLIB_TEST(test2_1.size() == 0);
+
+ test2_1.enable();
+
+
+ create_new_thread(&threadproc3<pipe>,&test2_1);
+ create_new_thread(&threadproc3<pipe>,&test2_1);
+
+
+ for (unsigned long i = 0; i < 100000; ++i)
+ {
+ a = i;
+ if (i%2 == 0)
+ test2_1.enqueue(a);
+ else
+ test2_1.enqueue_or_timeout(a,100000);
+ }
+
+ test2_1.wait_for_num_blocked_dequeues(2);
+ DLIB_TEST(test2_1.size() == 0);
+ test2_1.disable();
+
+ wait_for_threads();
+ DLIB_TEST(test2_1.size() == 0);
+
+ }
+
+ test.enable_enqueue();
+ test_0.enable_enqueue();
+ test_1.enable_enqueue();
+
+ DLIB_TEST(test.is_enabled());
+ DLIB_TEST(test.is_enqueue_enabled());
+ DLIB_TEST(test_0.is_enabled());
+ DLIB_TEST(test_0.is_enqueue_enabled());
+ DLIB_TEST(test_1.is_enabled());
+ DLIB_TEST(test_1.is_enqueue_enabled());
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test_0.size() == 0);
+ DLIB_TEST(test_1.size() == 0);
+ DLIB_TEST(test.max_size() == 10);
+ DLIB_TEST(test_0.max_size() == 0);
+ DLIB_TEST(test_1.max_size() == 1);
+
+
+ for (int i = 0; i < 100; ++i)
+ {
+ a = 1;
+ test.enqueue_or_timeout(a,0);
+ a = 1;
+ test_0.enqueue_or_timeout(a,0);
+ a = 1;
+ test_1.enqueue_or_timeout(a,0);
+ }
+
+ DLIB_TEST_MSG(test.size() == 10,"size: " << test.size() );
+ DLIB_TEST_MSG(test_0.size() == 0,"size: " << test.size() );
+ DLIB_TEST_MSG(test_1.size() == 1,"size: " << test.size() );
+
+ for (int i = 0; i < 10; ++i)
+ {
+ a = 0;
+ DLIB_TEST(test.enqueue_or_timeout(a,10) == false);
+ a = 0;
+ DLIB_TEST(test_0.enqueue_or_timeout(a,10) == false);
+ a = 0;
+ DLIB_TEST(test_1.enqueue_or_timeout(a,10) == false);
+ }
+
+ DLIB_TEST_MSG(test.size() == 10,"size: " << test.size() );
+ DLIB_TEST_MSG(test_0.size() == 0,"size: " << test.size() );
+ DLIB_TEST_MSG(test_1.size() == 1,"size: " << test.size() );
+
+ for (int i = 0; i < 10; ++i)
+ {
+ a = 0;
+ DLIB_TEST(test.dequeue_or_timeout(a,0) == true);
+ DLIB_TEST(a == 1);
+ }
+
+ DLIB_TEST(test.max_size() == 10);
+ DLIB_TEST(test_0.max_size() == 0);
+ DLIB_TEST(test_1.max_size() == 1);
+
+ a = 0;
+ DLIB_TEST(test_1.dequeue_or_timeout(a,0) == true);
+
+ DLIB_TEST(test.max_size() == 10);
+ DLIB_TEST(test_0.max_size() == 0);
+ DLIB_TEST(test_1.max_size() == 1);
+
+
+ DLIB_TEST_MSG(a == 1,"a: " << a);
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test_0.size() == 0);
+ DLIB_TEST(test_1.size() == 0);
+
+ DLIB_TEST(test.dequeue_or_timeout(a,0) == false);
+ DLIB_TEST(test_0.dequeue_or_timeout(a,0) == false);
+ DLIB_TEST(test_1.dequeue_or_timeout(a,0) == false);
+ DLIB_TEST(test.dequeue_or_timeout(a,10) == false);
+ DLIB_TEST(test_0.dequeue_or_timeout(a,10) == false);
+ DLIB_TEST(test_1.dequeue_or_timeout(a,10) == false);
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test_0.size() == 0);
+ DLIB_TEST(test_1.size() == 0);
+
+ DLIB_TEST(found_error == false);
+
+
+
+
+ {
+ test.enable();
+ test.enable_enqueue();
+ test.empty();
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_enabled() == true);
+ DLIB_TEST(test.is_enqueue_enabled() == true);
+ DLIB_TEST(test.is_dequeue_enabled() == true);
+ test.disable_dequeue();
+ dlog << LINFO << "Make sure disable_dequeue() works right...";
+ DLIB_TEST(test.is_dequeue_enabled() == false);
+ DLIB_TEST(test.dequeue(a) == false);
+ test.wait_until_empty();
+ a = 4;
+ test.enqueue(a);
+ test.wait_until_empty();
+ test.wait_for_num_blocked_dequeues(4);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(test.dequeue(a) == false);
+ DLIB_TEST(test.dequeue_or_timeout(a,10000) == false);
+ DLIB_TEST(test.size() == 1);
+ a = 0;
+ test.enable_dequeue();
+ DLIB_TEST(test.is_dequeue_enabled() == true);
+ DLIB_TEST(test.dequeue(a) == true);
+ DLIB_TEST(a == 4);
+ test_1.wait_until_empty();
+ }
+ {
+ test_1.enable();
+ test_1.enable_enqueue();
+ test_1.empty();
+ DLIB_TEST(test_1.size() == 0);
+ DLIB_TEST(test_1.is_enabled() == true);
+ DLIB_TEST(test_1.is_enqueue_enabled() == true);
+ DLIB_TEST(test_1.is_dequeue_enabled() == true);
+ test_1.disable_dequeue();
+ dlog << LINFO << "Make sure disable_dequeue() works right...";
+ DLIB_TEST(test_1.is_dequeue_enabled() == false);
+ DLIB_TEST(test_1.dequeue(a) == false);
+ a = 4;
+ test_1.wait_for_num_blocked_dequeues(4);
+ test_1.wait_for_num_blocked_dequeues(0);
+ test_1.enqueue(a);
+ test_1.wait_until_empty();
+ DLIB_TEST(test_1.size() == 1);
+ DLIB_TEST(test_1.dequeue(a) == false);
+ DLIB_TEST(test_1.dequeue_or_timeout(a,10000) == false);
+ DLIB_TEST(test_1.size() == 1);
+ a = 0;
+ test_1.enable_dequeue();
+ DLIB_TEST(test_1.is_dequeue_enabled() == true);
+ DLIB_TEST(test_1.dequeue(a) == true);
+ DLIB_TEST(a == 4);
+ test_1.wait_until_empty();
+ }
+
+ }
+
+
+
+
+ class pipe_tester : public tester
+ {
+ public:
+ pipe_tester (
+ ) :
+ tester ("test_pipe",
+ "Runs tests on the pipe component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ pipe_kernel_test<dlib::pipe<int> >();
+
+ do_zero_size_test_with_timeouts();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/pixel.cpp b/ml/dlib/dlib/test/pixel.cpp
new file mode 100644
index 000000000..40772b130
--- /dev/null
+++ b/ml/dlib/dlib/test/pixel.cpp
@@ -0,0 +1,777 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/pixel.h>
+#include <dlib/matrix.h>
+#include <dlib/image_io.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.pixel");
+
+
+ void pixel_test (
+ )
+ /*!
+ ensures
+ - runs tests on pixel objects and functions for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ unsigned char p_gray;
+ unsigned short p_gray16;
+ long p_int;
+ float p_float;
+ signed char p_schar;
+ rgb_pixel p_rgb,p_rgb2;
+ hsi_pixel p_hsi, p_hsi2;
+ rgb_alpha_pixel p_rgba;
+ lab_pixel p_lab, p_lab2;
+
+ assign_pixel(p_int, 0.0f);
+ assign_pixel(p_float, 0.0f);
+ assign_pixel(p_schar, 0);
+
+ assign_pixel(p_gray, -2);
+ assign_pixel(p_rgb,0);
+ assign_pixel(p_hsi, -4);
+ assign_pixel(p_rgba, p_int);
+ assign_pixel(p_gray16,0);
+ assign_pixel(p_lab,-400);
+
+ DLIB_TEST(p_int == 0);
+ DLIB_TEST(p_float == 0);
+ DLIB_TEST(p_schar == 0);
+
+ DLIB_TEST(p_gray == 0);
+ DLIB_TEST(p_gray16 == 0);
+
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 0);
+ DLIB_TEST(p_rgb.blue == 0);
+
+ DLIB_TEST(p_rgba.red == 0);
+ DLIB_TEST(p_rgba.green == 0);
+ DLIB_TEST(p_rgba.blue == 0);
+ DLIB_TEST(p_rgba.alpha == 255);
+
+ DLIB_TEST(p_hsi.h == 0);
+ DLIB_TEST(p_hsi.s == 0);
+ DLIB_TEST(p_hsi.i == 0);
+
+ DLIB_TEST(p_lab.l == 0);
+ DLIB_TEST(p_lab.a == 128);
+ DLIB_TEST(p_lab.b == 128);
+
+ assign_pixel(p_gray,10);
+ assign_pixel(p_gray16,10);
+ assign_pixel(p_rgb,10);
+ assign_pixel(p_hsi,10);
+ assign_pixel(p_rgba,10);
+ assign_pixel(p_lab,10);
+
+ assign_pixel(p_int, -10);
+ assign_pixel(p_float, -10);
+ assign_pixel(p_schar, -10);
+
+ DLIB_TEST(p_int == -10);
+ DLIB_TEST(p_float == -10);
+ DLIB_TEST(p_schar == -10);
+
+ DLIB_TEST(p_gray == 10);
+ DLIB_TEST(p_gray16 == 10);
+
+ DLIB_TEST(p_rgb.red == 10);
+ DLIB_TEST(p_rgb.green == 10);
+ DLIB_TEST(p_rgb.blue == 10);
+
+ DLIB_TEST(p_rgba.red == 10);
+ DLIB_TEST(p_rgba.green == 10);
+ DLIB_TEST(p_rgba.blue == 10);
+ DLIB_TEST(p_rgba.alpha == 255);
+
+ DLIB_TEST(p_hsi.h == 0);
+ DLIB_TEST(p_hsi.s == 0);
+ DLIB_TEST(p_hsi.i == 10);
+
+ DLIB_TEST(p_lab.l == 10);
+ DLIB_TEST(p_lab.a == 128);
+ DLIB_TEST(p_lab.b == 128);
+
+ assign_pixel(p_gray16,12345);
+ DLIB_TEST(p_gray16 == 12345);
+
+ assign_pixel(p_float,3.141);
+ DLIB_TEST(p_float == 3.141f);
+
+ p_rgb.red = 255;
+ p_rgb.green = 100;
+ p_rgb.blue = 50;
+
+ p_rgba.alpha = 4;
+ assign_pixel(p_gray,p_rgb);
+ assign_pixel(p_rgb,p_rgb);
+ assign_pixel(p_rgba,p_rgb);
+ assign_pixel(p_hsi,p_rgb);
+ assign_pixel(p_lab,p_rgb);
+
+ assign_pixel(p_float,p_rgb);
+ assign_pixel(p_int,p_rgb);
+ assign_pixel(p_schar,p_rgb);
+
+ DLIB_TEST(p_schar == std::numeric_limits<signed char>::max());
+
+ DLIB_TEST(p_int == (255+100+50)/3);
+ DLIB_TEST_MSG(p_float == (255+100+50)/3, p_float - (255+100+50)/3);
+ DLIB_TEST(p_gray == (255+100+50)/3);
+
+ DLIB_TEST(p_rgb.red == 255);
+ DLIB_TEST(p_rgb.green == 100);
+ DLIB_TEST(p_rgb.blue == 50);
+
+ DLIB_TEST(p_rgba.red == 255);
+ DLIB_TEST(p_rgba.green == 100);
+ DLIB_TEST(p_rgba.blue == 50);
+ DLIB_TEST(p_rgba.alpha == 255);
+
+ DLIB_TEST(p_hsi.i > 0);
+ DLIB_TEST(p_hsi.s > 0);
+ DLIB_TEST(p_hsi.h > 0);
+
+ DLIB_TEST(p_lab.l > 0);
+ DLIB_TEST(p_lab.a > 0);
+ DLIB_TEST(p_lab.b > 0);
+
+ assign_pixel(p_rgb,0);
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 0);
+ DLIB_TEST(p_rgb.blue == 0);
+ assign_pixel(p_rgb, p_hsi);
+
+ DLIB_TEST_MSG(p_rgb.red > 251 ,(int)p_rgb.green);
+ DLIB_TEST_MSG(p_rgb.green > 96 && p_rgb.green < 104,(int)p_rgb.green);
+ DLIB_TEST_MSG(p_rgb.blue > 47 && p_rgb.blue < 53,(int)p_rgb.green);
+
+ assign_pixel(p_rgb,0);
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 0);
+ DLIB_TEST(p_rgb.blue == 0);
+
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST_MSG(p_rgb.red > 251 ,(int)p_rgb.green);
+ DLIB_TEST_MSG(p_rgb.green > 96 && p_rgb.green < 104,(int)p_rgb.green);
+ DLIB_TEST_MSG(p_rgb.blue > 47 && p_rgb.blue < 53,(int)p_rgb.green);
+
+ assign_pixel(p_hsi2, p_hsi);
+ DLIB_TEST(p_hsi.h == p_hsi2.h);
+ DLIB_TEST(p_hsi.s == p_hsi2.s);
+ DLIB_TEST(p_hsi.i == p_hsi2.i);
+ assign_pixel(p_hsi,0);
+ DLIB_TEST(p_hsi.h == 0);
+ DLIB_TEST(p_hsi.s == 0);
+ DLIB_TEST(p_hsi.i == 0);
+ assign_pixel(p_hsi, p_rgba);
+
+ DLIB_TEST(p_hsi.h == p_hsi2.h);
+ DLIB_TEST(p_hsi.s == p_hsi2.s);
+ DLIB_TEST(p_hsi.i == p_hsi2.i);
+
+ assign_pixel(p_lab2, p_lab);
+ DLIB_TEST(p_lab.l == p_lab2.l);
+ DLIB_TEST(p_lab.a == p_lab2.a);
+ DLIB_TEST(p_lab.b == p_lab2.b);
+ assign_pixel(p_lab,0);
+ DLIB_TEST(p_lab.l == 0);
+ DLIB_TEST(p_lab.a == 128);
+ DLIB_TEST(p_lab.b == 128);
+ assign_pixel(p_lab, p_rgba);
+
+ DLIB_TEST(p_lab.l == p_lab2.l);
+ DLIB_TEST(p_lab.a == p_lab2.a);
+ DLIB_TEST(p_lab.b == p_lab2.b);
+
+ assign_pixel(p_rgba, 100);
+ assign_pixel(p_gray, 10);
+ assign_pixel(p_rgb, 10);
+ assign_pixel(p_hsi, 10);
+
+ assign_pixel(p_schar, 10);
+ assign_pixel(p_float, 10);
+ assign_pixel(p_int, 10);
+
+ p_rgba.alpha = 0;
+ assign_pixel(p_gray, p_rgba);
+ DLIB_TEST(p_gray == 10);
+ assign_pixel(p_schar, p_rgba);
+ DLIB_TEST(p_schar == 10);
+ assign_pixel(p_int, p_rgba);
+ DLIB_TEST(p_int == 10);
+ assign_pixel(p_float, p_rgba);
+ DLIB_TEST(p_float == 10);
+ assign_pixel(p_rgb, p_rgba);
+ DLIB_TEST(p_rgb.red == 10);
+ DLIB_TEST(p_rgb.green == 10);
+ DLIB_TEST(p_rgb.blue == 10);
+
+ assign_pixel(p_hsi, p_rgba);
+ assign_pixel(p_hsi2, p_rgb);
+ DLIB_TEST(p_hsi.h == 0);
+ DLIB_TEST(p_hsi.s == 0);
+ DLIB_TEST_MSG(p_hsi.i < p_hsi2.i+2 && p_hsi.i > p_hsi2.i -2,(int)p_hsi.i << " " << (int)p_hsi2.i);
+
+ // this value corresponds to RGB(10,10,10)
+ p_lab.l = 7;
+ p_lab.a = 128;
+ p_lab.b = 128;
+
+ assign_pixel(p_lab, p_rgba);
+ assign_pixel(p_lab2, p_rgb);
+ DLIB_TEST(p_lab.a == 128);
+ DLIB_TEST(p_lab.b == 128);
+ DLIB_TEST_MSG(p_lab.l < p_lab2.l+2 && p_lab.l > p_lab2.l -2,(int)p_lab.l << " " << (int)p_lab2.l);
+
+ assign_pixel(p_lab, 128);
+ DLIB_TEST(p_lab.l == 128);
+ DLIB_TEST(p_lab.a == 128);
+ DLIB_TEST(p_lab.b == 128);
+ assign_pixel(p_rgb, p_lab);
+ //Lab midpoint (50,0,0) is not same as RGB midpoint (127,127,127)
+ DLIB_TEST(p_rgb.red == 119);
+ DLIB_TEST(p_rgb.green == 119);
+ DLIB_TEST(p_rgb.blue == 119);
+
+ //Lab limit values test
+ //red, green, blue, yellow, black, white
+ p_lab.l = 84;
+ p_lab.a = 164;
+ p_lab.b = 56;
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 64);
+ DLIB_TEST(p_rgb.blue == 194);
+
+ p_lab.l = 255;
+ p_lab.a = 0;
+ p_lab.b = 0;
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 255);
+ DLIB_TEST(p_rgb.blue == 255);
+
+ p_lab.l = 0;
+ p_lab.a = 255;
+ p_lab.b = 0;
+
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 0);
+ DLIB_TEST(p_rgb.blue == 195);
+
+ p_lab.l = 0;
+ p_lab.a = 0;
+ p_lab.b = 255;
+
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 45);
+ DLIB_TEST(p_rgb.blue == 0);
+
+ p_lab.l = 255;
+ p_lab.a = 255;
+ p_lab.b = 0;
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST(p_rgb.red == 255);
+ DLIB_TEST(p_rgb.green == 139);
+ DLIB_TEST(p_rgb.blue == 255);
+
+ p_lab.l = 0;
+ p_lab.a = 255;
+ p_lab.b = 255;
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST(p_rgb.red == 132);
+ DLIB_TEST(p_rgb.green == 0);
+ DLIB_TEST(p_rgb.blue == 0);
+
+ p_lab.l = 255;
+ p_lab.a = 0;
+ p_lab.b = 255;
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 255);
+ DLIB_TEST(p_rgb.blue == 0);
+
+ p_lab.l = 255;
+ p_lab.a = 255;
+ p_lab.b = 255;
+ assign_pixel(p_rgb, p_lab);
+ DLIB_TEST(p_rgb.red == 255);
+ DLIB_TEST(p_rgb.green == 70);
+ DLIB_TEST(p_rgb.blue == 0);
+
+ //RGB limit tests
+ p_rgb.red = 0;
+ p_rgb.green = 0;
+ p_rgb.blue = 0;
+ assign_pixel(p_lab, p_rgb);
+ assign_pixel(p_rgb2, p_lab);
+ DLIB_TEST(p_rgb2.red < 3);
+ DLIB_TEST(p_rgb2.green < 3);
+ DLIB_TEST(p_rgb2.blue < 3);
+
+ p_rgb.red = 255;
+ p_rgb.green = 0;
+ p_rgb.blue = 0;
+ assign_pixel(p_lab, p_rgb);
+ assign_pixel(p_rgb2, p_lab);
+ DLIB_TEST(p_rgb2.red > 252);
+ DLIB_TEST(p_rgb2.green < 3);
+ DLIB_TEST(p_rgb2.blue < 3);
+
+ p_rgb.red = 0;
+ p_rgb.green = 255;
+ p_rgb.blue = 0;
+ assign_pixel(p_lab, p_rgb);
+ assign_pixel(p_rgb2, p_lab);
+ DLIB_TEST(p_rgb2.red < 8);
+ DLIB_TEST(p_rgb2.green > 252);
+ DLIB_TEST(p_rgb2.blue < 5);
+
+ p_rgb.red = 0;
+ p_rgb.green = 0;
+ p_rgb.blue = 255;
+ assign_pixel(p_lab, p_rgb);
+ assign_pixel(p_rgb2, p_lab);
+ DLIB_TEST(p_rgb2.red < 3);
+ DLIB_TEST(p_rgb2.green < 3);
+ DLIB_TEST(p_rgb2.blue > 252);
+
+ p_rgb.red = 255;
+ p_rgb.green = 255;
+ p_rgb.blue = 0;
+ assign_pixel(p_lab, p_rgb);
+ assign_pixel(p_rgb2, p_lab);
+ DLIB_TEST(p_rgb2.red > 252);
+ DLIB_TEST(p_rgb2.green > 252);
+ DLIB_TEST(p_rgb2.blue < 9);
+
+ p_rgb.red = 0;
+ p_rgb.green = 255;
+ p_rgb.blue = 255;
+ assign_pixel(p_lab, p_rgb);
+ assign_pixel(p_rgb2, p_lab);
+ DLIB_TEST(p_rgb2.red < 5);
+ DLIB_TEST(p_rgb2.green > 252);
+ DLIB_TEST(p_rgb2.blue > 252);
+
+ p_rgb.red = 255;
+ p_rgb.green = 0;
+ p_rgb.blue = 255;
+ assign_pixel(p_lab, p_rgb);
+ assign_pixel(p_rgb2, p_lab);
+ DLIB_TEST(p_rgb2.red> 252);
+ DLIB_TEST(p_rgb2.green < 6);
+ DLIB_TEST(p_rgb2.blue > 252);
+
+ p_rgb.red = 255;
+ p_rgb.green = 255;
+ p_rgb.blue = 255;
+ assign_pixel(p_lab, p_rgb);
+ assign_pixel(p_rgb2, p_lab);
+ DLIB_TEST(p_rgb2.red > 252 );
+ DLIB_TEST(p_rgb2.green> 252);
+ DLIB_TEST(p_rgb2.blue > 252);
+
+
+ assign_pixel(p_rgba, 100);
+ assign_pixel(p_gray, 10);
+ assign_pixel(p_schar, 10);
+ assign_pixel(p_float, 10);
+ assign_pixel(p_int, 10);
+
+ assign_pixel(p_rgb, 10);
+ p_rgba.alpha = 128;
+ assign_pixel(p_gray, p_rgba);
+ assign_pixel(p_schar, p_rgba);
+ assign_pixel(p_float, p_rgba);
+ assign_pixel(p_int, p_rgba);
+ assign_pixel(p_rgb, p_rgba);
+ DLIB_TEST(p_gray == (100 + 10)/2);
+ DLIB_TEST(p_schar == (100 + 10)/2);
+ DLIB_TEST(p_int == (100 + 10)/2);
+ DLIB_TEST(p_float == (100 + 10)/2);
+ DLIB_TEST(p_rgb.red == (100 + 10)/2);
+ DLIB_TEST(p_rgb.green == (100 + 10)/2);
+ DLIB_TEST(p_rgb.blue == (100 + 10)/2);
+
+ assign_pixel(p_rgba, 100);
+ assign_pixel(p_gray, 10);
+ assign_pixel(p_schar, 10);
+ assign_pixel(p_int, 10);
+ assign_pixel(p_float, 10);
+ assign_pixel(p_rgb, 10);
+ DLIB_TEST(p_rgba.alpha == 255);
+ assign_pixel(p_gray, p_rgba);
+ assign_pixel(p_schar, p_rgba);
+ assign_pixel(p_int, p_rgba);
+ assign_pixel(p_float, p_rgba);
+ assign_pixel(p_rgb, p_rgba);
+ DLIB_TEST(p_gray == 100);
+ DLIB_TEST(p_schar == 100);
+ DLIB_TEST(p_int == 100);
+ DLIB_TEST(p_float == 100);
+ DLIB_TEST(p_rgb.red == 100);
+ DLIB_TEST(p_rgb.green == 100);
+ DLIB_TEST(p_rgb.blue == 100);
+
+
+ p_rgb.red = 1;
+ p_rgb.green = 2;
+ p_rgb.blue = 3;
+
+ p_rgba.red = 4;
+ p_rgba.green = 5;
+ p_rgba.blue = 6;
+ p_rgba.alpha = 7;
+
+ p_gray = 8;
+ p_schar = 8;
+ p_int = 8;
+ p_float = 8;
+
+ p_hsi.h = 9;
+ p_hsi.s = 10;
+ p_hsi.i = 11;
+
+ p_lab.l = 10;
+ p_lab.a = 9;
+ p_lab.b = 8;
+
+ ostringstream sout;
+ serialize(p_rgb,sout);
+ serialize(p_rgba,sout);
+ serialize(p_gray,sout);
+ serialize(p_schar,sout);
+ serialize(p_int,sout);
+ serialize(p_float,sout);
+ serialize(p_hsi,sout);
+ serialize(p_lab,sout);
+
+ assign_pixel(p_rgb,0);
+ assign_pixel(p_rgba,0);
+ assign_pixel(p_gray,0);
+ assign_pixel(p_schar,0);
+ assign_pixel(p_int,0);
+ assign_pixel(p_float,0);
+ assign_pixel(p_hsi,0);
+ assign_pixel(p_lab,0);
+
+ istringstream sin(sout.str());
+
+ deserialize(p_rgb,sin);
+ deserialize(p_rgba,sin);
+ deserialize(p_gray,sin);
+ deserialize(p_schar,sin);
+ deserialize(p_int,sin);
+ deserialize(p_float,sin);
+ deserialize(p_hsi,sin);
+ deserialize(p_lab,sin);
+
+ DLIB_TEST(p_rgb.red == 1);
+ DLIB_TEST(p_rgb.green == 2);
+ DLIB_TEST(p_rgb.blue == 3);
+
+ DLIB_TEST(p_rgba.red == 4);
+ DLIB_TEST(p_rgba.green == 5);
+ DLIB_TEST(p_rgba.blue == 6);
+ DLIB_TEST(p_rgba.alpha == 7);
+
+ DLIB_TEST(p_gray == 8);
+ DLIB_TEST(p_schar == 8);
+ DLIB_TEST(p_int == 8);
+ DLIB_TEST(p_float == 8);
+
+ DLIB_TEST(p_hsi.h == 9);
+ DLIB_TEST(p_hsi.s == 10);
+ DLIB_TEST(p_hsi.i == 11);
+
+ DLIB_TEST(p_lab.l == 10);
+ DLIB_TEST(p_lab.a == 9);
+ DLIB_TEST(p_lab.b == 8);
+
+ {
+ matrix<double,1,1> m_gray, m_schar, m_int, m_float;
+ matrix<double,3,1> m_rgb, m_hsi, m_lab;
+
+ m_gray = pixel_to_vector<double>(p_gray);
+ m_schar = pixel_to_vector<double>(p_schar);
+ m_int = pixel_to_vector<double>(p_int);
+ m_float = pixel_to_vector<double>(p_float);
+
+ m_hsi = pixel_to_vector<double>(p_hsi);
+ m_rgb = pixel_to_vector<double>(p_rgb);
+ m_lab = pixel_to_vector<double>(p_lab);
+
+ DLIB_TEST(m_gray(0) == p_gray);
+ DLIB_TEST(m_float(0) == p_float);
+ DLIB_TEST(m_int(0) == p_int);
+ DLIB_TEST(m_schar(0) == p_schar);
+
+ DLIB_TEST(m_rgb(0) == p_rgb.red);
+ DLIB_TEST(m_rgb(1) == p_rgb.green);
+ DLIB_TEST(m_rgb(2) == p_rgb.blue);
+ DLIB_TEST(m_hsi(0) == p_hsi.h);
+ DLIB_TEST(m_hsi(1) == p_hsi.s);
+ DLIB_TEST(m_hsi(2) == p_hsi.i);
+ DLIB_TEST(m_lab(0) == p_lab.l);
+ DLIB_TEST(m_lab(1) == p_lab.a);
+ DLIB_TEST(m_lab(2) == p_lab.b);
+
+ DLIB_TEST(p_rgb.red == 1);
+ DLIB_TEST(p_rgb.green == 2);
+ DLIB_TEST(p_rgb.blue == 3);
+
+ DLIB_TEST(p_rgba.red == 4);
+ DLIB_TEST(p_rgba.green == 5);
+ DLIB_TEST(p_rgba.blue == 6);
+ DLIB_TEST(p_rgba.alpha == 7);
+
+ DLIB_TEST(p_gray == 8);
+ DLIB_TEST(p_int == 8);
+ DLIB_TEST(p_float == 8);
+ DLIB_TEST(p_schar == 8);
+
+ DLIB_TEST(p_hsi.h == 9);
+ DLIB_TEST(p_hsi.s == 10);
+ DLIB_TEST(p_hsi.i == 11);
+
+ DLIB_TEST(p_lab.l == 10);
+ DLIB_TEST(p_lab.a == 9);
+ DLIB_TEST(p_lab.b == 8);
+
+ assign_pixel(p_gray,0);
+ assign_pixel(p_hsi,0);
+ assign_pixel(p_rgb,0);
+ assign_pixel(p_lab,0);
+
+ vector_to_pixel(p_gray, m_gray);
+ vector_to_pixel(p_hsi, m_hsi);
+ vector_to_pixel(p_rgb, m_rgb);
+ vector_to_pixel(p_lab, m_lab);
+
+ DLIB_TEST(p_rgb.red == 1);
+ DLIB_TEST(p_rgb.green == 2);
+ DLIB_TEST(p_rgb.blue == 3);
+
+ DLIB_TEST(p_rgba.red == 4);
+ DLIB_TEST(p_rgba.green == 5);
+ DLIB_TEST(p_rgba.blue == 6);
+ DLIB_TEST(p_rgba.alpha == 7);
+
+ DLIB_TEST(p_gray == 8);
+
+ DLIB_TEST(p_hsi.h == 9);
+ DLIB_TEST(p_hsi.s == 10);
+ DLIB_TEST(p_hsi.i == 11);
+
+ DLIB_TEST(p_lab.l == 10);
+ DLIB_TEST(p_lab.a == 9);
+ DLIB_TEST(p_lab.b == 8);
+ }
+
+
+
+
+ {
+ unsigned char p_gray;
+ unsigned short p_gray16;
+ long p_int;
+ float p_float;
+ signed char p_schar;
+ rgb_pixel p_rgb;
+ hsi_pixel p_hsi, p_hsi2;
+ rgb_alpha_pixel p_rgba;
+ lab_pixel p_lab;
+
+
+ assign_pixel(p_gray, 0);
+ assign_pixel(p_gray16, 0);
+ assign_pixel(p_int, 0);
+ assign_pixel(p_float, 0);
+ assign_pixel(p_schar, 0);
+ assign_pixel(p_rgb, 0);
+ assign_pixel(p_hsi, 0);
+ assign_pixel(p_lab, 0);
+
+
+ assign_pixel(p_gray, 100);
+ assign_pixel(p_schar, p_gray);
+ DLIB_TEST(p_schar == 100);
+
+ assign_pixel(p_gray, 200);
+ assign_pixel(p_schar, p_gray);
+ DLIB_TEST(p_schar == std::numeric_limits<signed char>::max());
+
+ assign_pixel(p_int, p_gray);
+ DLIB_TEST(p_int == 200);
+
+ assign_pixel(p_float, p_gray);
+ DLIB_TEST(p_float == 200);
+
+ assign_pixel(p_rgb, p_float);
+ DLIB_TEST(p_rgb.red == 200);
+ DLIB_TEST(p_rgb.green == 200);
+ DLIB_TEST(p_rgb.blue == 200);
+
+ p_schar = 0;
+ assign_pixel(p_schar, p_rgb);
+ DLIB_TEST(p_schar == std::numeric_limits<signed char>::max());
+
+
+ p_schar = -10;
+ assign_pixel(p_float, p_schar);
+ DLIB_TEST(p_float == -10);
+ assign_pixel(p_int, p_schar);
+ DLIB_TEST(p_int == -10);
+ assign_pixel(p_schar, p_schar);
+ DLIB_TEST(p_schar == -10);
+ assign_pixel(p_gray, p_schar);
+ DLIB_TEST(p_gray == 0);
+
+ assign_pixel(p_rgb, p_schar);
+ DLIB_TEST(p_rgb.red == 0);
+ DLIB_TEST(p_rgb.green == 0);
+ DLIB_TEST(p_rgb.blue == 0);
+
+ assign_pixel(p_gray16, p_schar);
+ DLIB_TEST(p_gray16 == 0);
+
+ DLIB_TEST(get_pixel_intensity(p_float) == -10);
+ DLIB_TEST(get_pixel_intensity(p_int) == -10);
+ DLIB_TEST(get_pixel_intensity(p_schar) == -10);
+ DLIB_TEST(get_pixel_intensity(p_rgb) == 0);
+ DLIB_TEST(get_pixel_intensity(p_gray16) == 0);
+
+ p_rgb.red = 100;
+ p_rgb.green = 100;
+ p_rgb.blue = 100;
+ DLIB_TEST(get_pixel_intensity(p_rgb) == 100);
+ p_rgb.red = 1;
+ p_rgb.green = 2;
+ p_rgb.blue = 3;
+ DLIB_TEST(get_pixel_intensity(p_rgb) == 2);
+ p_rgba.alpha = 100;
+ p_rgba.red = 100;
+ p_rgba.green = 100;
+ p_rgba.blue = 100;
+ DLIB_TEST(get_pixel_intensity(p_rgba) == 100);
+ p_rgba.red = 1;
+ p_rgba.green = 2;
+ p_rgba.blue = 3;
+ p_rgba.alpha = 0;
+ DLIB_TEST(get_pixel_intensity(p_rgba) == 2);
+ p_hsi.h = 123;
+ p_hsi.s = 100;
+ p_hsi.i = 84;
+ DLIB_TEST(get_pixel_intensity(p_hsi) == 84);
+
+ p_lab.l = 123;
+ p_lab.a = 100;
+ p_lab.b = 84;
+ DLIB_TEST(get_pixel_intensity(p_lab) == 123);
+
+ p_float = 54.25;
+ DLIB_TEST(get_pixel_intensity(p_float) == 54.25);
+
+ assign_pixel(p_gray, p_float);
+ DLIB_TEST(get_pixel_intensity(p_gray) == 54);
+
+ assign_pixel_intensity(p_float, -1000);
+ assign_pixel_intensity(p_schar, -100);
+ assign_pixel_intensity(p_int, -10000);
+ assign_pixel_intensity(p_gray, -100);
+
+ p_rgba.red = 10;
+ p_rgba.green = 10;
+ p_rgba.blue = 10;
+ p_rgba.alpha = 0;
+ DLIB_TEST_MSG(get_pixel_intensity(p_rgba) == 10, (int)get_pixel_intensity(p_rgba));
+ assign_pixel_intensity(p_rgba, 2);
+ DLIB_TEST_MSG(p_rgba.red == 2, (int)p_rgba.red);
+ DLIB_TEST_MSG(p_rgba.green == 2, (int)p_rgba.green);
+ DLIB_TEST_MSG(p_rgba.blue == 2, (int)p_rgba.blue);
+ DLIB_TEST_MSG(p_rgba.alpha == 0, (int)p_rgba.alpha);
+ DLIB_TEST_MSG(get_pixel_intensity(p_rgba) == 2, (int)get_pixel_intensity(p_rgba));
+
+ DLIB_TEST(p_float == -1000);
+ DLIB_TEST(get_pixel_intensity(p_float) == -1000);
+ DLIB_TEST(p_schar == -100);
+ DLIB_TEST(get_pixel_intensity(p_schar) == -100);
+ DLIB_TEST(p_int == -10000);
+ DLIB_TEST(get_pixel_intensity(p_int) == -10000);
+ DLIB_TEST(p_gray == 0);
+ assign_pixel_intensity(p_gray, 1000);
+ DLIB_TEST(p_gray == 255);
+ DLIB_TEST(get_pixel_intensity(p_gray) == 255);
+
+ assign_pixel_intensity(p_float, p_gray);
+ DLIB_TEST(p_float == 255);
+ DLIB_TEST(get_pixel_intensity(p_float) == 255);
+
+ assign_pixel_intensity(p_int, p_gray);
+ DLIB_TEST(p_int == 255);
+ DLIB_TEST(get_pixel_intensity(p_int) == 255);
+
+
+ p_float = 1e10;
+ assign_pixel(p_schar, p_float);
+ DLIB_TEST(p_schar == std::numeric_limits<signed char>::max());
+
+ p_float = -1e10;
+ assign_pixel(p_schar, p_float);
+ DLIB_TEST(p_schar == std::numeric_limits<signed char>::min());
+
+ double p_double = 1e200;
+ assign_pixel(p_float, p_double);
+ DLIB_TEST(p_float == std::numeric_limits<float>::max());
+
+ p_double = -1e200;
+ assign_pixel(p_float, p_double);
+ DLIB_TEST(p_float == -std::numeric_limits<float>::max());
+ }
+
+
+ }
+
+
+
+
+ class pixel_tester : public tester
+ {
+ public:
+ pixel_tester (
+ ) :
+ tester ("test_pixel",
+ "Runs tests on the pixel objects and functions.")
+ {}
+
+ void perform_test (
+ )
+ {
+ pixel_test();
+ }
+ } a;
+
+}
diff --git a/ml/dlib/dlib/test/probabilistic.cpp b/ml/dlib/dlib/test/probabilistic.cpp
new file mode 100644
index 000000000..e8a24829a
--- /dev/null
+++ b/ml/dlib/dlib/test/probabilistic.cpp
@@ -0,0 +1,123 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+#include "checkerboard.h"
+#include <dlib/statistics.h>
+
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.probabilistic");
+
+// ----------------------------------------------------------------------------------------
+
+ class test_probabilistic : public tester
+ {
+ public:
+ test_probabilistic (
+ ) :
+ tester ("test_probabilistic",
+ "Runs tests on the probabilistic trainer adapter.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+
+
+ typedef double scalar_type;
+ typedef matrix<scalar_type,2,1> sample_type;
+
+ std::vector<sample_type> x;
+ std::vector<matrix<double,0,1> > x_linearized;
+ std::vector<scalar_type> y;
+
+ get_checkerboard_problem(x,y, 1000, 2);
+
+ random_subset_selector<sample_type> rx;
+ random_subset_selector<scalar_type> ry;
+ rx.set_max_size(x.size());
+ ry.set_max_size(x.size());
+
+ dlog << LINFO << "pos labels: "<< sum(mat(y) == +1);
+ dlog << LINFO << "neg labels: "<< sum(mat(y) == -1);
+
+ for (unsigned long i = 0; i < x.size(); ++i)
+ {
+ rx.add(x[i]);
+ ry.add(y[i]);
+ }
+
+ const scalar_type gamma = 2.0;
+
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+ krr_trainer<kernel_type> krr_trainer;
+ krr_trainer.use_classification_loss_for_loo_cv();
+ krr_trainer.set_kernel(kernel_type(gamma));
+ krr_trainer.set_basis(randomly_subsample(x, 100));
+ probabilistic_decision_function<kernel_type> df;
+
+ dlog << LINFO << "cross validation: " << cross_validate_trainer(krr_trainer, rx,ry, 4);
+ print_spinner();
+
+ running_stats<scalar_type> rs_pos, rs_neg;
+
+ print_spinner();
+ df = probabilistic(krr_trainer,3).train(x, y);
+ for (unsigned long i = 0; i < x.size(); ++i)
+ {
+ if (y[i] > 0)
+ rs_pos.add(df(x[i]));
+ else
+ rs_neg.add(df(x[i]));
+ }
+ dlog << LINFO << "rs_pos.mean(): "<< rs_pos.mean();
+ dlog << LINFO << "rs_neg.mean(): "<< rs_neg.mean();
+ DLIB_TEST_MSG(rs_pos.mean() > 0.95, rs_pos.mean());
+ DLIB_TEST_MSG(rs_neg.mean() < 0.05, rs_neg.mean());
+ rs_pos.clear();
+ rs_neg.clear();
+
+
+ print_spinner();
+ df = probabilistic(krr_trainer,3).train(rx, ry);
+ for (unsigned long i = 0; i < x.size(); ++i)
+ {
+ if (y[i] > 0)
+ rs_pos.add(df(x[i]));
+ else
+ rs_neg.add(df(x[i]));
+ }
+ dlog << LINFO << "rs_pos.mean(): "<< rs_pos.mean();
+ dlog << LINFO << "rs_neg.mean(): "<< rs_neg.mean();
+ DLIB_TEST_MSG(rs_pos.mean() > 0.95, rs_pos.mean());
+ DLIB_TEST_MSG(rs_neg.mean() < 0.05, rs_neg.mean());
+ rs_pos.clear();
+ rs_neg.clear();
+
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/pyramid_down.cpp b/ml/dlib/dlib/test/pyramid_down.cpp
new file mode 100644
index 000000000..c026a8162
--- /dev/null
+++ b/ml/dlib/dlib/test/pyramid_down.cpp
@@ -0,0 +1,424 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/image_transforms.h>
+//#include <dlib/gui_widgets.h>
+#include <dlib/rand.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.pyramid_down");
+
+// ----------------------------------------------------------------------------------------
+
+void test_pyramid_down_grayscale()
+{
+ array2d<unsigned char> img, down;
+ pyramid_down<2> pyr;
+
+ img.set_size(300,264);
+
+ assign_all_pixels(img, 10);
+
+ pyr(img, down);
+
+ DLIB_TEST(std::abs(down.nr()*2 - img.nr()) < 5);
+ DLIB_TEST(std::abs(down.nc()*2 - img.nc()) < 5);
+
+ rectangle rect1 = get_rect(img);
+ rectangle rect2 = pyr.rect_up(get_rect(down));
+ double overlap = rect1.intersect(rect2).area() / (double)(rect1 + rect2).area();
+ DLIB_TEST(overlap > 0.95);
+
+ rect1 = get_rect(down);
+ rect2 = pyr.rect_down(get_rect(img));
+ overlap = rect1.intersect(rect2).area() / (double)(rect1 + rect2).area();
+ DLIB_TEST(overlap > 0.95);
+
+ DLIB_TEST(min(mat(down)) == 10);
+ DLIB_TEST(max(mat(down)) == 10);
+}
+
+void test_pyramid_down_rgb()
+{
+ array2d<rgb_pixel> img;
+ array2d<bgr_pixel> down;
+ pyramid_down<2> pyr;
+
+ img.set_size(231, 351);
+
+ assign_all_pixels(img, rgb_pixel(1,2,3));
+
+ pyr(img, down);
+
+ DLIB_TEST(std::abs(down.nr()*2 - img.nr()) < 5);
+ DLIB_TEST(std::abs(down.nc()*2 - img.nc()) < 5);
+
+ rectangle rect1 = get_rect(img);
+ rectangle rect2 = pyr.rect_up(get_rect(down));
+ double overlap = rect1.intersect(rect2).area() / (double)(rect1 + rect2).area();
+ DLIB_TEST(overlap > 0.95);
+
+ rect1 = get_rect(down);
+ rect2 = pyr.rect_down(get_rect(img));
+ overlap = rect1.intersect(rect2).area() / (double)(rect1 + rect2).area();
+ DLIB_TEST(overlap > 0.95);
+
+ bool pixels_match = true;
+ for (long r = 0; r < down.nr(); ++r)
+ {
+ for (long c = 0; c < down.nc(); ++c)
+ {
+ if (down[r][c].red != 1 ||
+ down[r][c].green != 2 ||
+ down[r][c].blue != 3 )
+ {
+ pixels_match = false;
+ }
+ }
+ }
+ DLIB_TEST(pixels_match);
+}
+
+// ----------------------------------------------------------------------------
+
+template <typename image_type>
+rgb_pixel mean_pixel (
+ const image_type& img,
+ const rectangle& rect
+)
+{
+ long red = 0;
+ long green = 0;
+ long blue = 0;
+ for (long r = rect.top(); r <= rect.bottom(); ++r)
+ {
+ for (long c = rect.left(); c <= rect.right(); ++c)
+ {
+ red += img[r][c].red;
+ green += img[r][c].green;
+ blue += img[r][c].blue;
+ }
+ }
+
+ const long n = rect.area();
+ return rgb_pixel(red/n, green/n, blue/n);
+}
+
+// ----------------------------------------------------------------------------
+
+template <typename pyramid_down_type>
+void test_pyramid_down_rgb2()
+{
+ array2d<rgb_pixel> img, img3;
+ array2d<unsigned char> img2, img4;
+
+
+ img.set_size(300,400);
+ assign_all_pixels(img, 0);
+ rectangle rect1 = centered_rect( 10,10, 14, 14);
+ rectangle rect2 = centered_rect( 100,100, 34, 42);
+ rectangle rect3 = centered_rect( 310,215, 65, 21);
+
+ fill_rect(img, rect1, rgb_pixel(255,0,0));
+ fill_rect(img, rect2, rgb_pixel(0,255,0));
+ fill_rect(img, rect3, rgb_pixel(0,0,255));
+
+
+
+ pyramid_down_type pyr;
+
+ pyr(img, img2);
+ pyr(img, img3);
+
+
+ DLIB_TEST(((rect1.tl_corner() - pyr.rect_down(pyr.rect_up(rect1,2),2).tl_corner()).length()) < 1);
+ DLIB_TEST(((rect1.br_corner() - pyr.rect_down(pyr.rect_up(rect1,2),2).br_corner()).length()) < 1);
+ DLIB_TEST(((rect2.tl_corner() - pyr.rect_down(pyr.rect_up(rect2,2),2).tl_corner()).length()) < 1);
+ DLIB_TEST(((rect2.br_corner() - pyr.rect_down(pyr.rect_up(rect2,2),2).br_corner()).length()) < 1);
+ DLIB_TEST(((rect3.tl_corner() - pyr.rect_down(pyr.rect_up(rect3,2),2).tl_corner()).length()) < 1);
+ DLIB_TEST(((rect3.br_corner() - pyr.rect_down(pyr.rect_up(rect3,2),2).br_corner()).length()) < 1);
+
+ rect1 = shrink_rect(pyr.rect_down(rect1),1);
+ rect2 = shrink_rect(pyr.rect_down(rect2),1);
+ rect3 = shrink_rect(pyr.rect_down(rect3),1);
+
+ DLIB_TEST(rect1.area() > 10);
+ DLIB_TEST(rect2.area() > 10);
+ DLIB_TEST(rect3.area() > 10);
+
+ /*
+ image_window my_window(img);
+ image_window win2(img2);
+ image_window win3(img3);
+ win2.add_overlay(image_window::overlay_rect(rect1, rgb_pixel(255,0,0)));
+ win2.add_overlay(image_window::overlay_rect(rect2, rgb_pixel(255,0,0)));
+ win2.add_overlay(image_window::overlay_rect(rect3, rgb_pixel(255,0,0)));
+ win3.add_overlay(image_window::overlay_rect(rect1, rgb_pixel(255,0,0)));
+ win3.add_overlay(image_window::overlay_rect(rect2, rgb_pixel(255,0,0)));
+ win3.add_overlay(image_window::overlay_rect(rect3, rgb_pixel(255,0,0)));
+ */
+
+
+ DLIB_TEST(std::abs((int)mean(subm(matrix_cast<long>(mat(img2)),rect1)) - 255/3) < 3);
+ DLIB_TEST(std::abs((int)mean(subm(matrix_cast<long>(mat(img2)),rect2)) - 255/3) < 3);
+ DLIB_TEST(std::abs((int)mean(subm(matrix_cast<long>(mat(img2)),rect3)) - 255/3) < 3);
+ assign_image(img4, img);
+ DLIB_TEST(std::abs((int)mean(mat(img4)) - mean(mat(img2))) < 2);
+
+
+ rgb_pixel mean1 = mean_pixel(img3, rect1);
+ rgb_pixel mean2 = mean_pixel(img3, rect2);
+ rgb_pixel mean3 = mean_pixel(img3, rect3);
+ rgb_pixel mean_all_true = mean_pixel(img, get_rect(img));
+ rgb_pixel mean_all = mean_pixel(img3, get_rect(img3));
+ DLIB_TEST(mean1.red > 250);
+ DLIB_TEST(mean1.green < 3);
+ DLIB_TEST(mean1.blue < 3);
+
+ DLIB_TEST(mean2.red < 3);
+ DLIB_TEST(mean2.green > 250);
+ DLIB_TEST(mean2.blue < 3);
+
+ DLIB_TEST(mean3.red < 3);
+ DLIB_TEST(mean3.green < 3);
+ DLIB_TEST(mean3.blue > 250);
+
+ DLIB_TEST(std::abs((int)mean_all_true.red - mean_all.red) < 1);
+ DLIB_TEST(std::abs((int)mean_all_true.green - mean_all.green) < 1);
+ DLIB_TEST(std::abs((int)mean_all_true.blue - mean_all.blue) < 1);
+
+ //my_window.wait_until_closed();
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+template <typename pyramid_down_type>
+void test_pyramid_down_grayscale2()
+{
+ array2d<unsigned char> img;
+ array2d<unsigned char> img2, img4;
+
+
+ img.set_size(300,400);
+ assign_all_pixels(img, 0);
+ rectangle rect1 = centered_rect( 10,10, 14, 14);
+ rectangle rect2 = centered_rect( 100,100, 34, 42);
+ rectangle rect3 = centered_rect( 310,215, 65, 21);
+
+ fill_rect(img, rect1, 255);
+ fill_rect(img, rect2, 170);
+ fill_rect(img, rect3, 100);
+
+
+
+ pyramid_down_type pyr;
+
+ pyr(img, img2);
+
+
+ DLIB_TEST(((rect1.tl_corner() - pyr.rect_down(pyr.rect_up(rect1,2),2).tl_corner()).length()) < 1);
+ DLIB_TEST(((rect1.br_corner() - pyr.rect_down(pyr.rect_up(rect1,2),2).br_corner()).length()) < 1);
+ DLIB_TEST(((rect2.tl_corner() - pyr.rect_down(pyr.rect_up(rect2,2),2).tl_corner()).length()) < 1);
+ DLIB_TEST(((rect2.br_corner() - pyr.rect_down(pyr.rect_up(rect2,2),2).br_corner()).length()) < 1);
+ DLIB_TEST(((rect3.tl_corner() - pyr.rect_down(pyr.rect_up(rect3,2),2).tl_corner()).length()) < 1);
+ DLIB_TEST(((rect3.br_corner() - pyr.rect_down(pyr.rect_up(rect3,2),2).br_corner()).length()) < 1);
+
+ rect1 = shrink_rect(pyr.rect_down(rect1),1);
+ rect2 = shrink_rect(pyr.rect_down(rect2),1);
+ rect3 = shrink_rect(pyr.rect_down(rect3),1);
+
+ DLIB_TEST(rect1.area() > 10);
+ DLIB_TEST(rect2.area() > 10);
+ DLIB_TEST(rect3.area() > 10);
+
+ /*
+ image_window my_window(img);
+ image_window win2(img2);
+ win2.add_overlay(image_window::overlay_rect(rect1, rgb_pixel(255,0,0)));
+ win2.add_overlay(image_window::overlay_rect(rect2, rgb_pixel(255,0,0)));
+ win2.add_overlay(image_window::overlay_rect(rect3, rgb_pixel(255,0,0)));
+ */
+
+
+ DLIB_TEST(std::abs((int)mean(subm(matrix_cast<long>(mat(img2)),rect1)) - 255) <= 3);
+ DLIB_TEST(std::abs((int)mean(subm(matrix_cast<long>(mat(img2)),rect2)) - 170) < 3);
+ DLIB_TEST(std::abs((int)mean(subm(matrix_cast<long>(mat(img2)),rect3)) - 100) < 3);
+ assign_image(img4, img);
+ DLIB_TEST(std::abs((int)mean(mat(img4)) - mean(mat(img2))) < 2);
+
+
+ //my_window.wait_until_closed();
+
+
+
+ // make sure the coordinate mapping is invertible when it should be
+ for (int l = 0; l < 4; ++l)
+ {
+ for (long x = -10; x <= 10; ++x)
+ {
+ for (long y = -10; y <= 10; ++y)
+ {
+ DLIB_TEST_MSG(point(pyr.point_down(pyr.point_up(point(x,y),l),l)) == point(x,y),
+ point(x,y) << " " << pyr.point_up(point(x,y),l) << " " << pyr.point_down(pyr.point_up(point(x,y),l),l));
+ DLIB_TEST_MSG(point(pyr.point_down(point(pyr.point_up(point(x,y),l)),l)) == point(x,y),
+ point(x,y) << " " << pyr.point_up(point(x,y),l) << " " << pyr.point_down(point(pyr.point_up(point(x,y),l)),l));
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+
+template <typename pyramid_down_type>
+void test_pyr_sizes()
+{
+ dlib::rand rnd;
+
+ for (int iter = 0; iter < 20; ++iter)
+ {
+ long nr = rnd.get_random_32bit_number()%10+40;
+ long nc = rnd.get_random_32bit_number()%10+40;
+
+ array2d<unsigned char> img(nr,nc), img2;
+ assign_all_pixels(img,0);
+
+ pyramid_down_type pyr;
+
+ pyr(img, img2);
+ find_pyramid_down_output_image_size(pyr, nr, nc);
+ DLIB_TEST(img2.nr() == nr);
+ DLIB_TEST(img2.nc() == nc);
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+template <typename pyramid_down_type>
+void test_pyramid_down_small_sizes()
+{
+ print_spinner();
+ // just make sure it doesn't get messed up with small images. This test
+ // is only really useful if asserts are enabled.
+ pyramid_down_type pyr;
+
+ for (int size = 0; size < 20; ++size)
+ {
+ array2d<unsigned char> img1(size,size);
+ array2d<rgb_pixel> img2(size,size);
+
+ array2d<unsigned char> out1;
+ array2d<rgb_pixel> out2;
+
+ assign_all_pixels(img1, 0);
+ assign_all_pixels(img2, 0);
+
+ pyr(img1, out1);
+ pyr(img2, out2);
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+
+
+ class test_pyramid_down : public tester
+ {
+ public:
+ test_pyramid_down (
+ ) :
+ tester ("test_pyramid_down",
+ "Runs tests on the pyramid_down() function.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ test_pyramid_down_grayscale();
+ print_spinner();
+ test_pyramid_down_rgb();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_small_sizes<pyramid_down<2> >();";
+ test_pyramid_down_small_sizes<pyramid_down<2> >();
+ dlog << LINFO << "call test_pyramid_down_small_sizes<pyramid_down<3> >();";
+ test_pyramid_down_small_sizes<pyramid_down<3> >();
+ dlog << LINFO << "call test_pyramid_down_small_sizes<pyramid_down<4> >();";
+ test_pyramid_down_small_sizes<pyramid_down<4> >();
+ dlog << LINFO << "call test_pyramid_down_small_sizes<pyramid_down<5> >();";
+ test_pyramid_down_small_sizes<pyramid_down<5> >();
+ dlog << LINFO << "call test_pyramid_down_small_sizes<pyramid_disable>();";
+ test_pyramid_down_small_sizes<pyramid_disable>();
+ dlog << LINFO << "call test_pyramid_down_small_sizes<pyramid_down<9> >();";
+ test_pyramid_down_small_sizes<pyramid_down<9> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_rgb2<pyramid_down<2> >();";
+ test_pyramid_down_rgb2<pyramid_down<2> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_rgb2<pyramid_down<3> >();";
+ test_pyramid_down_rgb2<pyramid_down<3> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_rgb2<pyramid_down<4> >();";
+ test_pyramid_down_rgb2<pyramid_down<4> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_rgb2<pyramid_down<5> >();";
+ test_pyramid_down_rgb2<pyramid_down<5> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_rgb2<pyramid_down<8> >();";
+ test_pyramid_down_rgb2<pyramid_down<8> >();
+
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_grayscale2<pyramid_down<2> >();";
+ test_pyramid_down_grayscale2<pyramid_down<2> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_grayscale2<pyramid_down<3> >();";
+ test_pyramid_down_grayscale2<pyramid_down<3> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_grayscale2<pyramid_down<4> >();";
+ test_pyramid_down_grayscale2<pyramid_down<4> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_grayscale2<pyramid_down<5> >();";
+ test_pyramid_down_grayscale2<pyramid_down<5> >();
+
+ print_spinner();
+ dlog << LINFO << "call test_pyramid_down_grayscale2<pyramid_down<6> >();";
+ test_pyramid_down_grayscale2<pyramid_down<6> >();
+
+
+ test_pyr_sizes<pyramid_down<1>>();
+ test_pyr_sizes<pyramid_down<2>>();
+ test_pyr_sizes<pyramid_down<3>>();
+ test_pyr_sizes<pyramid_down<4>>();
+ test_pyr_sizes<pyramid_down<5>>();
+ test_pyr_sizes<pyramid_down<6>>();
+ test_pyr_sizes<pyramid_down<7>>();
+ test_pyr_sizes<pyramid_down<8>>();
+ test_pyr_sizes<pyramid_down<28>>();
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/queue.cpp b/ml/dlib/dlib/test/queue.cpp
new file mode 100644
index 000000000..efcdf6054
--- /dev/null
+++ b/ml/dlib/dlib/test/queue.cpp
@@ -0,0 +1,426 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/queue.h>
+#include <dlib/memory_manager_global.h>
+
+#include "tester.h"
+
+// This is called an unnamed-namespace and it has the effect of making everything inside this file "private"
+// so that everything you declare will have static linkage. Thus we won't have any multiply
+// defined symbol errors coming out of the linker when we try to compile the test suite.
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ // Declare the logger we will use in this test. The name of the tester
+ // should start with "test."
+ logger dlog("test.queue");
+
+ template <
+ typename queue
+ >
+ void queue_sort_test (
+ )
+ /*!
+ requires
+ - queue is an implementation of queue/queue_sort_abstract.h
+ is instantiated with int
+ ensures
+ - runs tests on queue for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+ srand(static_cast<unsigned int>(time(0)));
+
+ queue q,q2;
+
+ enumerable<int>& e = q;
+
+ // I will use these DLIB_TEST_MSG macros to assert that conditions are true. If they are
+ // false then it means we have detected an error in the queue object. CASSERT
+ // will then throw an exception which we will catch at the end of this function and
+ // report as an error/failed test.
+ DLIB_TEST(e.at_start() == true);
+
+ int a = 0;
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q.at_start() == true);
+ DLIB_TEST(q.current_element_valid() == false);
+
+ q.sort();
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q.at_start() == true);
+ DLIB_TEST(q.current_element_valid() == false);
+
+ DLIB_TEST (q.move_next() == false);
+ DLIB_TEST (q.move_next() == false);
+ DLIB_TEST (q.move_next() == false);
+ DLIB_TEST (q.move_next() == false);
+ DLIB_TEST (q.move_next() == false);
+ DLIB_TEST (q.move_next() == false);
+
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q.at_start() == false);
+ DLIB_TEST(q.current_element_valid() == false);
+
+
+ q.reset();
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q.at_start() == true);
+ DLIB_TEST(q.current_element_valid() == false);
+
+
+
+
+
+
+
+
+
+
+
+ q.clear();
+ q2.clear();
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q2.size() == 0);
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ int a = i;
+ q.enqueue(a);
+ }
+
+ q2.cat(q);
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q2.size() == 10000);
+
+ int g = 0;
+ while (q2.move_next())
+ {
+ DLIB_TEST_MSG(q2.element() == g,g);
+ ++g;
+ }
+
+ for (int i = 0;i < 10000; ++i)
+ {
+ int a = 0;
+ q2.dequeue(a);
+ DLIB_TEST(a == i);
+ }
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q2.size() == 0);
+ q.clear();
+ q2.clear();
+
+
+
+
+ print_spinner();
+
+
+ dlog << LTRACE << "creating big pre-sorted queue";
+ q.clear();
+ DLIB_TEST(q.size() == 0);
+
+ for (int i = 0; i < 10000; ++i)
+ {
+ int a = i;
+ q.enqueue(a);
+ }
+
+ dlog << LTRACE << "sorting already sorted queue";
+ q.sort();
+
+
+ dlog << LTRACE << "done sorting, checking the results";
+ for (int i = 0; i < 10000; ++i)
+ {
+ q.dequeue(a);
+ DLIB_TEST(a == i);
+ }
+
+
+ q.clear();
+ dlog << LTRACE << "done with the big pre-sorted queue test";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ q.clear();
+ q2.clear();
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q2.size() == 0);
+
+ for (int i = 0; i < 1; ++i)
+ {
+ int a = i;
+ q.enqueue(a);
+ }
+
+ q2.cat(q);
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q2.size() == 1);
+
+
+
+ g = 0;
+ while (q2.move_next())
+ {
+ DLIB_TEST_MSG(q2.element() == g,g);
+ ++g;
+ }
+
+ for (int i = 0;i < 1; ++i)
+ {
+ int a = 0;
+ q2.dequeue(a);
+ DLIB_TEST(a == i);
+ }
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q2.size() == 0);
+ q.clear();
+ q2.clear();
+
+
+
+
+
+
+
+ print_spinner();
+
+
+
+
+
+
+
+
+
+
+
+ for (int j = 0; j < 3; ++j)
+ {
+ for (int i = 0; i < 10000; ++i)
+ {
+ a = ::rand();
+ q.enqueue(a);
+ }
+
+ while (q.move_next()) ;
+
+ DLIB_TEST(q.at_start() == false);
+
+ q.sort();
+
+ DLIB_TEST(q.at_start() == true);
+
+ // serialize the state of q, then clear q, then
+ // load the state back into q.
+ ostringstream sout;
+ serialize(q,sout);
+ DLIB_TEST(q.at_start() == true);
+ istringstream sin(sout.str());
+ q.clear();
+ deserialize(q,sin);
+
+
+ DLIB_TEST(q.at_start() == true);
+
+ a = 0;
+ int last = 0;
+ while (q.move_next())
+ {
+ ++a;
+ DLIB_TEST_MSG(last <= q.element(),"items weren't actually sorted");
+ last = q.element();
+ DLIB_TEST(q.current_element_valid() == true);
+ DLIB_TEST(q.at_start() == false);
+ DLIB_TEST(q.current_element_valid() == true);
+
+
+ }
+ DLIB_TEST_MSG(a == 10000,"some items were lost between the sorting and iterating");
+
+
+ DLIB_TEST(q.size() == 10000);
+ swap(q,q2);
+ DLIB_TEST(q2.at_start() == false);
+ DLIB_TEST(q2.current_element_valid() == false);
+
+ DLIB_TEST (q2.move_next() == false);
+ DLIB_TEST (q2.move_next() == false);
+ DLIB_TEST (q2.move_next() == false);
+ DLIB_TEST (q2.move_next() == false);
+ DLIB_TEST (q2.move_next() == false);
+ DLIB_TEST (q2.move_next() == false);
+
+
+ DLIB_TEST(q2.size() == 10000);
+ DLIB_TEST(q2.at_start() == false);
+ DLIB_TEST(q2.current_element_valid() == false);
+
+ q2.clear();
+
+ q.swap(q2);
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q.at_start() == true);
+ DLIB_TEST(q.current_element_valid() == false);
+ }
+
+
+
+ print_spinner();
+
+
+
+ // try the above code but this time with just one element
+ // in the queue
+ for (int j = 0; j < 3; ++j)
+ {
+ for (int i = 0; i < 1; ++i)
+ {
+ a = ::rand();
+ q.enqueue(a);
+ }
+
+ q.sort();
+
+ a = 0;
+ int last = 0;
+ while (q.move_next())
+ {
+ ++a;
+ DLIB_TEST_MSG(last <= q.element(),"items weren't actually sorted");
+ DLIB_TEST(q.current_element_valid() == true);
+
+ }
+ DLIB_TEST_MSG(a == 1,"some items were lost between the sorting and iterating");
+
+
+ DLIB_TEST(q.size() == 1);
+ DLIB_TEST(q.at_start() == false);
+ DLIB_TEST(q.current_element_valid() == false);
+
+ q.clear();
+
+ DLIB_TEST(q.size() == 0);
+ DLIB_TEST(q.at_start() == true);
+ DLIB_TEST(q.current_element_valid() == false);
+ }
+
+
+ print_spinner();
+
+ {
+ q.clear();
+ remover<int>& go = q;
+ for (int i = 0; i < 100; ++i)
+ {
+ int a = 3;
+ q.enqueue(a);
+ }
+ DLIB_TEST(go.size() == 100);
+ for (int i = 0; i < 100; ++i)
+ {
+ int a = 9;
+ q.remove_any(a);
+ DLIB_TEST(a == 3);
+ }
+ DLIB_TEST(go.size() == 0);
+ }
+
+ }
+
+
+ struct factory
+ {
+ template <typename U>
+ struct return_type {
+ typedef typename memory_manager<U>::kernel_3c type;
+ };
+
+ template <typename U>
+ static typename return_type<U>::type* get_instance (
+ )
+ {
+ static typename return_type<U>::type a;
+ return &a;
+ }
+ };
+
+
+
+
+ class queue_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a test for the queue object. When it is constructed
+ it adds itself into the testing framework. The command line switch is
+ specified as test_queue by passing that string to the tester constructor.
+ !*/
+ public:
+ queue_tester (
+ ) :
+ tester ("test_queue",
+ "Runs tests on the queue component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ // There are multiple implementations of the queue object so use
+ // the templated function defined above to test them all and report
+ // a failed test if any of them don't pass.
+
+ typedef dlib::memory_manager_global<char,factory>::kernel_1a mm;
+
+
+ dlog << LINFO << "testing sort_1a_c";
+ queue_sort_test<queue<int, mm>::sort_1a_c> ();
+ dlog << LINFO << "testing sort_1a";
+ queue_sort_test<queue<int, mm>::sort_1a>();
+ dlog << LINFO << "testing sort_1b";
+ queue_sort_test<queue<int, mm>::sort_1b> ();
+ dlog << LINFO << "testing sort_1b_c";
+ queue_sort_test<queue<int, mm>::sort_1b_c>();
+ dlog << LINFO << "testing sort_1c";
+ queue_sort_test<queue<int, mm>::sort_1c> ();
+ dlog << LINFO << "testing sort_1c_c";
+ queue_sort_test<queue<int, mm>::sort_1c_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/rand.cpp b/ml/dlib/dlib/test/rand.cpp
new file mode 100644
index 000000000..db051c530
--- /dev/null
+++ b/ml/dlib/dlib/test/rand.cpp
@@ -0,0 +1,436 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <cmath>
+#include <dlib/rand.h>
+#include <dlib/compress_stream.h>
+#include <dlib/hash.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.rand");
+
+ void check_bpp (
+ const std::string str
+ )
+ {
+ istringstream rdata;
+ ostringstream sout;
+ rdata.str(str);
+ double compressed_size;
+ compress_stream::kernel_1a cs1;
+ compress_stream::kernel_2a cs2;
+
+ compress_stream_kernel_1<
+ entropy_encoder_model_kernel_5<257,entropy_encoder::kernel_1a,4000000,4>,
+ entropy_decoder_model_kernel_5<257,entropy_decoder::kernel_1a,4000000,4>,
+ crc32::kernel_1a
+ > cs3;
+
+
+ print_spinner();
+
+ rdata.clear();
+ rdata.seekg(0);
+ sout.clear();
+ sout.str("");
+ cs1.compress(rdata,sout);
+ compressed_size = sout.str().size();
+ compressed_size *= 8;
+ compressed_size /= str.size();
+ DLIB_TEST_MSG(compressed_size >= 8, "order 0 bps: " << compressed_size);
+ dlog << LINFO << "order 0: " << compressed_size;
+
+ print_spinner();
+
+ rdata.clear();
+ rdata.seekg(0);
+ sout.clear();
+ sout.str("");
+ cs2.compress(rdata,sout);
+ compressed_size = sout.str().size();
+ compressed_size *= 8;
+ compressed_size /= str.size();
+ DLIB_TEST_MSG(compressed_size >= 8, "order 1 bps: " << compressed_size);
+ dlog << LINFO << "order 1: " << compressed_size;
+
+ print_spinner();
+
+ rdata.clear();
+ rdata.seekg(0);
+ sout.clear();
+ sout.str("");
+ cs3.compress(rdata,sout);
+ compressed_size = sout.str().size();
+ compressed_size *= 8;
+ compressed_size /= str.size();
+ DLIB_TEST_MSG(compressed_size >= 8, "order 4 bps: " << compressed_size);
+ dlog << LINFO << "order 4: " << compressed_size;
+
+ }
+
+ template <
+ typename rand
+ >
+ void rand_test (
+ )
+ /*!
+ requires
+ - rand is an implementation of rand/rand_kernel_abstract.h
+ is instantiated with int
+ ensures
+ - runs tests on rand for compliance with the specs
+ !*/
+ {
+
+ ostringstream seed;
+ seed << (unsigned int)time(0);
+
+ ostringstream sout;
+
+
+ rand r, r2;
+ DLIB_TEST(r.get_seed() == "");
+ r.set_seed(seed.str());
+
+ DLIB_TEST(r.get_seed() == seed.str());
+ r.clear();
+ DLIB_TEST(r.get_seed() == "");
+ swap(r,r2);
+ DLIB_TEST(r.get_seed() == "");
+ r.set_seed(seed.str());
+ DLIB_TEST(r.get_seed() == seed.str());
+ swap(r,r2);
+ DLIB_TEST(r2.get_seed() == seed.str());
+ DLIB_TEST(r.get_seed() == "");
+ swap(r,r2);
+ DLIB_TEST(r.get_seed() == seed.str());
+ DLIB_TEST(r2.get_seed() == "");
+
+ print_spinner();
+ unsigned long size = 100000;
+ for (unsigned long i = 0; i < size; ++i)
+ {
+ uint32 ch = r.get_random_32bit_number();
+ sout.write((char*)&ch,4);
+ }
+
+ check_bpp(sout.str());
+ sout.clear();
+ sout.str("");
+
+ print_spinner();
+ for (unsigned long i = 0; i < size; ++i)
+ {
+ uint16 ch = r.get_random_16bit_number();
+ sout.write((char*)&ch,2);
+ }
+
+ check_bpp(sout.str());
+ sout.clear();
+ sout.str("");
+
+ print_spinner();
+ for (unsigned long i = 0; i < size; ++i)
+ {
+ unsigned char ch = r.get_random_8bit_number();
+ sout.write((char*)&ch,1);
+ }
+
+ check_bpp(sout.str());
+ sout.clear();
+ sout.str("");
+
+
+ // make sure the things can serialize right
+ {
+ r.clear();
+ r2.clear();
+
+
+ for (int i =0; i < 1000; ++i)
+ {
+ r.get_random_32bit_number();
+ r.get_random_gaussian();
+ }
+
+ ostringstream sout;
+ serialize(r, sout);
+
+ istringstream sin(sout.str());
+ deserialize(r2, sin);
+
+
+ for (int i =0; i < 1000; ++i)
+ {
+ DLIB_TEST(r.get_random_32bit_number() == r2.get_random_32bit_number());
+ DLIB_TEST(std::abs(r.get_random_gaussian() - r2.get_random_gaussian()) < 1e-14);
+ }
+ }
+
+
+ // make sure calling clear() and set_seed("") do the same thing
+ {
+ r.clear();
+ r2.set_seed("");
+ rand r3;
+
+
+ DLIB_TEST(r.get_seed() == r2.get_seed());
+ DLIB_TEST(r.get_seed() == r3.get_seed());
+
+
+ for (int i =0; i < 1000; ++i)
+ {
+ const uint32 num1 = r.get_random_32bit_number();
+ const uint32 num2 = r2.get_random_32bit_number();
+ const uint32 num3 = r3.get_random_32bit_number();
+ DLIB_TEST( num1 == num2);
+ DLIB_TEST( num1 == num3);
+ }
+ }
+
+ }
+
+
+ template <typename rand_type>
+ void test_normal_numbers(
+ rand_type& rnd
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test normality";
+ double cnt1 = 0; // num <= -1.2
+ double cnt2 = 0; // num <= -0.5
+ double cnt3 = 0; // num <= 0
+ double cnt4 = 0; // num <= 0.5
+ double cnt5 = 0; // num <= 1.2
+
+ const unsigned long total = 1000000;
+ for (unsigned long i = 0; i < total; ++i)
+ {
+ const double r = rnd.get_random_gaussian();
+ if (r <= -1.2) cnt1 += 1;
+ if (r <= -0.5) cnt2 += 1;
+ if (r <= 0) cnt3 += 1;
+ if (r <= 0.5) cnt4 += 1;
+ if (r <= 1.2) cnt5 += 1;
+ }
+
+ cnt1 /= total;
+ cnt2 /= total;
+ cnt3 /= total;
+ cnt4 /= total;
+ cnt5 /= total;
+
+ dlog << LINFO << "cnt1: "<< cnt1;
+ dlog << LINFO << "cnt2: "<< cnt2;
+ dlog << LINFO << "cnt3: "<< cnt3;
+ dlog << LINFO << "cnt4: "<< cnt4;
+ dlog << LINFO << "cnt5: "<< cnt5;
+
+ DLIB_TEST(std::abs(cnt1 - 0.11507) < 0.001);
+ DLIB_TEST(std::abs(cnt2 - 0.30854) < 0.001);
+ DLIB_TEST(std::abs(cnt3 - 0.5) < 0.001);
+ DLIB_TEST(std::abs(cnt4 - 0.69146) < 0.001);
+ DLIB_TEST(std::abs(cnt5 - 0.88493) < 0.001);
+
+ }
+
+ void test_gaussian_random_hash()
+ {
+ print_spinner();
+ dlog << LINFO << "test_gaussian_random_hash()";
+ double cnt1 = 0; // num <= -1.2
+ double cnt2 = 0; // num <= -0.5
+ double cnt3 = 0; // num <= 0
+ double cnt4 = 0; // num <= 0.5
+ double cnt5 = 0; // num <= 1.2
+
+ const unsigned long total = 1000000;
+ for (unsigned long i = 0; i < total; ++i)
+ {
+ const double r = gaussian_random_hash(i,0,0);
+ if (r <= -1.2) cnt1 += 1;
+ if (r <= -0.5) cnt2 += 1;
+ if (r <= 0) cnt3 += 1;
+ if (r <= 0.5) cnt4 += 1;
+ if (r <= 1.2) cnt5 += 1;
+ }
+ for (unsigned long i = 0; i < total; ++i)
+ {
+ const double r = gaussian_random_hash(0,i,0);
+ if (r <= -1.2) cnt1 += 1;
+ if (r <= -0.5) cnt2 += 1;
+ if (r <= 0) cnt3 += 1;
+ if (r <= 0.5) cnt4 += 1;
+ if (r <= 1.2) cnt5 += 1;
+ }
+ for (unsigned long i = 0; i < total; ++i)
+ {
+ const double r = gaussian_random_hash(0,0,i);
+ if (r <= -1.2) cnt1 += 1;
+ if (r <= -0.5) cnt2 += 1;
+ if (r <= 0) cnt3 += 1;
+ if (r <= 0.5) cnt4 += 1;
+ if (r <= 1.2) cnt5 += 1;
+ }
+
+ cnt1 /= total*3;
+ cnt2 /= total*3;
+ cnt3 /= total*3;
+ cnt4 /= total*3;
+ cnt5 /= total*3;
+
+ dlog << LINFO << "cnt1: "<< cnt1;
+ dlog << LINFO << "cnt2: "<< cnt2;
+ dlog << LINFO << "cnt3: "<< cnt3;
+ dlog << LINFO << "cnt4: "<< cnt4;
+ dlog << LINFO << "cnt5: "<< cnt5;
+
+ DLIB_TEST(std::abs(cnt1 - 0.11507) < 0.001);
+ DLIB_TEST(std::abs(cnt2 - 0.30854) < 0.001);
+ DLIB_TEST(std::abs(cnt3 - 0.5) < 0.001);
+ DLIB_TEST(std::abs(cnt4 - 0.69146) < 0.001);
+ DLIB_TEST(std::abs(cnt5 - 0.88493) < 0.001);
+ }
+
+ void test_uniform_random_hash()
+ {
+ print_spinner();
+ dlog << LINFO << "test_uniform_random_hash()";
+ double cnt1 = 0; // num <= 0.2
+ double cnt2 = 0; // num <= 0.4
+ double cnt3 = 0; // num <= 0.6
+ double cnt4 = 0; // num <= 0.8
+ double cnt5 = 0; // num <= 1.0
+
+ double min_val = 10;
+ double max_val = 0;
+
+ const unsigned long total = 1000000;
+ for (unsigned long i = 0; i < total; ++i)
+ {
+ const double r = uniform_random_hash(i,0,0);
+ min_val = min(r,min_val);
+ max_val = max(r,max_val);
+
+ if (r <= 0.2) cnt1 += 1;
+ if (r <= 0.4) cnt2 += 1;
+ if (r <= 0.6) cnt3 += 1;
+ if (r <= 0.8) cnt4 += 1;
+ if (r <= 1.0) cnt5 += 1;
+ }
+ for (unsigned long i = 0; i < total; ++i)
+ {
+ const double r = uniform_random_hash(0,i,0);
+ min_val = min(r,min_val);
+ max_val = max(r,max_val);
+
+ if (r <= 0.2) cnt1 += 1;
+ if (r <= 0.4) cnt2 += 1;
+ if (r <= 0.6) cnt3 += 1;
+ if (r <= 0.8) cnt4 += 1;
+ if (r <= 1.0) cnt5 += 1;
+ }
+ for (unsigned long i = 0; i < total; ++i)
+ {
+ const double r = uniform_random_hash(0,0,i);
+ min_val = min(r,min_val);
+ max_val = max(r,max_val);
+
+ if (r <= 0.2) cnt1 += 1;
+ if (r <= 0.4) cnt2 += 1;
+ if (r <= 0.6) cnt3 += 1;
+ if (r <= 0.8) cnt4 += 1;
+ if (r <= 1.0) cnt5 += 1;
+ }
+
+ cnt1 /= total*3;
+ cnt2 /= total*3;
+ cnt3 /= total*3;
+ cnt4 /= total*3;
+ cnt5 /= total*3;
+
+ dlog << LINFO << "cnt1: "<< cnt1;
+ dlog << LINFO << "cnt2: "<< cnt2;
+ dlog << LINFO << "cnt3: "<< cnt3;
+ dlog << LINFO << "cnt4: "<< cnt4;
+ dlog << LINFO << "cnt5: "<< cnt5;
+ dlog << LINFO << "min_val: "<< min_val;
+ dlog << LINFO << "max_val: "<< max_val;
+
+ DLIB_TEST(std::abs(cnt1 - 0.2) < 0.001);
+ DLIB_TEST(std::abs(cnt2 - 0.4) < 0.001);
+ DLIB_TEST(std::abs(cnt3 - 0.6) < 0.001);
+ DLIB_TEST(std::abs(cnt4 - 0.8) < 0.001);
+ DLIB_TEST(std::abs(cnt5 - 1.0) < 0.001);
+ DLIB_TEST(std::abs(min_val - 0.0) < 0.001);
+ DLIB_TEST(std::abs(max_val - 1.0) < 0.001);
+ }
+
+ void test_get_integer()
+ {
+
+ print_spinner();
+ dlib::rand rnd;
+
+
+ int big_val = 0;
+ int small_val = 0;
+
+ const long long maxval = (((unsigned long long)1)<<62) + (((unsigned long long)1)<<61);
+ for (int i = 0; i < 10000000; ++i)
+ {
+ if (rnd.get_integer(maxval) > maxval/2)
+ ++big_val;
+ else
+ ++small_val;
+ }
+
+ // make sure there isn't any funny bias
+ DLIB_TEST(std::abs(big_val/(double)small_val - 1) < 0.001);
+
+ //cout << big_val/(double)small_val << endl;
+
+ }
+
+ class rand_tester : public tester
+ {
+ public:
+ rand_tester (
+ ) :
+ tester ("test_rand",
+ "Runs tests on the rand component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ rand_test<dlib::rand>();
+ rand_test<dlib::rand>();
+
+ dlib::rand rnd;
+ test_normal_numbers(rnd);
+ test_gaussian_random_hash();
+ test_uniform_random_hash();
+ test_get_integer();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/random_forest.cpp b/ml/dlib/dlib/test/random_forest.cpp
new file mode 100644
index 000000000..b3447bf5c
--- /dev/null
+++ b/ml/dlib/dlib/test/random_forest.cpp
@@ -0,0 +1,405 @@
+// Copyright (C) 2018 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <dlib/random_forest.h>
+#include <dlib/svm.h>
+#include <dlib/statistics.h>
+
+#include <sstream>
+#include <dlib/compress_stream.h>
+#include <dlib/base64.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+
+ logger dlog("test.random_forest");
+
+ const std::string get_decoded_string();
+
+// ----------------------------------------------------------------------------------------
+
+
+
+ class test_random_forest : public tester
+ {
+ public:
+ test_random_forest (
+ ) :
+ tester ("test_random_forest",
+ "Runs tests on the random forest tools.")
+ {}
+
+
+ void perform_test (
+ )
+ {
+ istringstream sin(get_decoded_string());
+
+ print_spinner();
+
+ typedef matrix<double,0,1> sample_type;
+ std::vector<double> labels;
+ std::vector<sample_type> samples;
+
+ deserialize(samples, sin);
+ deserialize(labels, sin);
+
+ DLIB_TEST(samples.size() == 506);
+
+ random_forest_regression_trainer<dense_feature_extractor> trainer;
+ trainer.set_num_trees(1000);
+ trainer.set_seed("random forest");
+
+ std::vector<double> oobs;
+ auto df = trainer.train(samples, labels, oobs);
+
+ DLIB_TEST(df.get_num_trees() == 1000);
+
+ auto result = test_regression_function(df, samples, labels);
+ // train: 2.239 0.987173 0.970669 1.1399
+ dlog << LINFO << "train: " << result;
+ DLIB_TEST_MSG(result(0) < 2.3, result(0));
+
+ running_stats<double> rs;
+ for (size_t i = 0; i < oobs.size(); ++i)
+ rs.add(std::pow(oobs[i]-labels[i],2.0));
+ dlog << LINFO << "OOB MSE: "<< rs.mean();
+ DLIB_TEST_MSG(rs.mean() < 10.2, rs.mean());
+
+ print_spinner();
+
+ stringstream ss;
+ serialize(df, ss);
+ decltype(df) df2;
+ deserialize(df2, ss);
+ DLIB_TEST(df2.get_num_trees() == 1000);
+ result = test_regression_function(df2, samples, labels);
+ // train: 2.239 0.987173 0.970669 1.1399
+ dlog << LINFO << "serialized train results: " << result;
+ DLIB_TEST_MSG(result(0) < 2.3, result(0));
+ }
+ } a;
+
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+
+ // This function returns the contents of the file './housing_data.dat'
+ const std::string get_decoded_string()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file './housing_data.dat' we want to decode and return.
+ sout << "AvlDWRK3FGmPtCL8V/RoXQLzsOKukA0zQosjXGZPM6yNf1U5LjdhRVloILZ5baZq5Tj0hLQGf1JY";
+ sout << "ggTd0DEbBez7lzvZ6hOBABkJ6U0aZAEeIMUL/K19h5gHhpwdWvcolJA+VbQVD4acLQFxcIgsgN8N";
+ sout << "2zjQsQCUkHGSGyop7/xrVZAJS4Nwy8qMWJyjgc/9mZXdDsaPWtSVTeoxpb3d94bDYdrEQ8T0Z6N1";
+ sout << "fCXCQo/3bus7NA+FJoOtw23DHMsYnsv+tfvaNzzzX7lc0cRPe8Pi5q9JDBs4Gc5bPh3Hw8QJz3n5";
+ sout << "beGJpU1KRHu9vq1zgFuavXvyZ1HQVHLj/yJRm4lL5eUv7CQeULGP9UmIkvVCJTZ4uw6mIFJyPYjN";
+ sout << "jjygWMfJ1dnlGpI/ZlaVNJaTEB28tNymV0UKeKb/Sg42s9+wNNQzWMBm5TRvqmplf/0Gx+4Tcmcd";
+ sout << "FtUb1pgkz6OB59Ko4L2hsxVQYYZHGpQt6QBMiubW7GVe2g4yWjRhqlQTh2sjceGRi26SFOrD+gnH";
+ sout << "9xZlbyKdlKlcT3nVfcKYziLKAjbmr5QIu+W6WR7M+p90CHkDrjkVK0WTSc23kOhuua5feG54aoht";
+ sout << "hcViWRpASVPXsKKJcl2yTlZ02uFQak5Lid/znCDmWQk0fjfzEZZNzgoCNVi8xCx68lH4Mjm3MdF4";
+ sout << "ExZqX0jsNlxDOwKp7TYIbhfY4/XdzFSi20CtxXbB3knkuggb+ru/u/6lh8rmqwLjsANqb2CWG0EH";
+ sout << "32i1/gmtlY54kAYG58GWB89klTnUwRImQv/QjJBrf8TwK0jUOjkrnOWgKWwNsK0jba54750QPal4";
+ sout << "SJFvmeBIR52/T2ZsC2iAQGQuod1IZtIfI2pn0dpkdWm/Y3JdelJ/EADtNjJch6maVoamxKmoWlVw";
+ sout << "TRoHTIzdsJKtQiewn21H8bFX7HzZ1yE3/iuSEeLPB7T7gnfrtCEEzqAWiUb/t7mXtqBqt6Kdk6By";
+ sout << "JZqE0KdtJ7MJ/yV1MHQ94ExDhYI0qaItZVGwyH8ETCzr6xqmue9hPD6SRq3oy+aQKvJxOqFMcqsj";
+ sout << "cL+/2S2F1frRgZDGCb6tB3TdMCJDhZoChQNmJ3hyoAdWXrPEysL0TW8LFSIItAylIRljMsXgnMRE";
+ sout << "RCkfYPdbweT71k6l7FiaAsqHeKh4w8CxKJkzhJeALEPLz4QvqFt6/DoFmhKTrX4xUk3M/Y+dU/LY";
+ sout << "3B/S+e6v9cWuluEGXDzgj/LKBeruPk7hcnhIilMmd3D8sew3tvOdIowxmM67lqW6fwExcK6oKPlT";
+ sout << "aDZcttWKTndVEKsUvnZr/PQ8sta49+GGSfkXw/MS0TAjTQ0Wck8wSJ2CMoUGBmVSKLSwEWvdAqdo";
+ sout << "lQLDxAVayR3GeKasJshQw69o/3d4JnUOBcU5ZJM0z2D51EDQM3lvmnB9dtiJ2rcypWG53ETvQqYc";
+ sout << "S3suPgaDqKmxZbRNvnfuYbG6+qPeHDN6WmdAt9Iw5XWdjlG6u8BGI6+vqY1C8J6pJ2p7ITUVBVCU";
+ sout << "NRYyXVhz0PQrzy5jFwbVeRZo3IV/bkPlHV4UujcSEOi67fqk4ixOzA2JsxYzei+Rsp1ahpK3Wmuk";
+ sout << "9ZEeqD1/xqqeosV5pvwcXhjjp4UJ0bGY0pEf7w9uDW0aZT+D8prSmTXGjFAQGiSBmfLFw1Yk2CyG";
+ sout << "V8RG7/7uxM6qyj9LYsNTGvdyD8DvQNEJ0v7J9IwCihdJAFhuKgqxlmkJx3mz6MiiIC19CuQKR0NC";
+ sout << "1/PG2wh7zEhnDwfINSR2b41ZDcm8/ky/k+xhJ6fi3ZqpSlkqyPRA/YAID9Dl7Ngn9/xeWQNXzEHD";
+ sout << "pn6aPHclBaDm5keUHlcN9d+vrxrRjV/GdRhs5M2eVRl47djEiYTaQ3Ua9Lg0oWBXYFkC1ncNhsIT";
+ sout << "tFLwx1Fc89lNwN3kHW91X3g1MMDFZoyzwBan2v/3DOZpPH4U1cPr1SbAPu0HITHK6pCUtMRY2/DZ";
+ sout << "9MTmm6FLeJhjiVma1+ALD4wYTNhebWkmX12jeDPT5gMyDhq3dYQKIvq83aVY1MQ2UroMDf9NVEdh";
+ sout << "V94rpEjw0ewZeDKHwPazkOU4q5m69VxwkKSbNzKZ1oe0P5s7j4Z44NYP3o7Qq8MPLi9l7QVKqge8";
+ sout << "6PqEdYoxGr9a/QDB7wcSdpcZTku0MippOZm1uG0zA2K6WlTmC/3lCm4m8EZBZXq6YkTjUpPreeio";
+ sout << "umUsmp+XbtJ1LWK3V5hMl0R67Fa6tBd6x9bP6/FSwjeYPHj8dz3nK0VLX+NC7+NjIPBkKgAcqs+1";
+ sout << "m9u/BA72sNE/cn7NgfgXPlHsho3reV8Iujq+MTN5iayeTH2fyG7XmV0RkpOY770bJEdugB4QlWWL";
+ sout << "nZgYd2yyNFlBcvXRKZpoG9cTWuzdxSbJnYdgKGLuPQ0B0BYwrSLnHEM8pboXCN4uIrALW6ipmKeO";
+ sout << "/S8bW4u73Bqgamnh7/pdLAoWo6EiD5C3uNrW0OYdnnSjhLHkV+krDhPQr6nAfjH/0vo+CXPDbMyW";
+ sout << "DmkJVgJ/cBt+EWNyIOeBLliqbe9zY6hqzGRt4b6cp1fDH/tbYMCsxhp0LIPnDNDouUQK3j+VBB3X";
+ sout << "E8NnCSzBa4SdhMNww7jbJea+RXqe+g1clXqkBf/ZitToTPmzHhYcPRAcvhLcRE0n/uWj7jbv5vOD";
+ sout << "swyUpiJaXQgRG77rh89xNVqz9qio6uP2xGdlyW0IENbxMYsGq+XKxNMAMHvfRh8JwakGw7ZI/Wn7";
+ sout << "8uWdjM2lNmenBCYSS9qe+2DKnqTxOSnm5ugsYr6IXftmlzev0ke2rRBfvllAv8GSY8GTJul+gbZV";
+ sout << "+3Wu8xZawgLFjngRph0aq4PviIwrMS1PhE5M7pC65E40uaY+xJv4rQGNCLF3/+SLvnLfTRdH0QZU";
+ sout << "r/hXG0BCcaWE4hb7HIzon9mNIZf2Eb+IWxAhUQ2/Nhe/hNTRx+DpB/8H2DurZPFK4nrOPvxmmzgA";
+ sout << "3VFL0kJjNfeXGlo2sSQEM8sDecXQkl47KGWROHIaJyRZAoBOBpMHxTXs//3aqWhlOZ88pftZEmSL";
+ sout << "K0sXXxS3BAKB8SLzu4VNPNdvmtT7Z4sHmfYj5NXayXS3V2d2646L2QW4jzzwHjpJ6p2/4mjKniFO";
+ sout << "TSQu1wKSv16L/QVbiwvg6wYgIL8cct+XSRSUGfvVgo9lAt+OHTIL7s/9A66jqdDmK3UnHcV8XOVN";
+ sout << "Wd+DnXOG7nI5shOiGHAqAAtuQZK9sAZZtyLmg68UN02ZroY0pUePwuGaBribKuKLDtcfMcDHwv0x";
+ sout << "lSlCkHu9SjsC1Qswk90Yx8YddYY1ePYaoez6xUAraj+zOLNuFCZtm6hGTQq+pPZ5xn/K6zzOvaos";
+ sout << "sxDaWBSNDEuOfAK2dHgctL6XKH7/kHAZxBa7CbTSe0zFuO1WbicRrqO1NpUyO9P1L82dv1VCSuyi";
+ sout << "Mtj7UNnywrmZmMBf5x5yYBdVwBUKIBy/sNJdrpDHbAi6MJoYzCai8TqTulNL8jGAzkjpXYRqPf99";
+ sout << "fXWRTzN1PMHjvEbNOBIX4OorGR4lj4E7i+d1DKaJjXCDgvJQTUGvRWdu7MOOkXPCmIlxFL9Wv2CB";
+ sout << "LpzzNp+I3NuLg2F30ratBBLoqIrnBBXb390pABYah8bRnARCUJLjFXugVqTWoMwAsrbS6sfdFRf8";
+ sout << "fKt/+Nx2vX8tRJBFFgBEbS2le05ekg7HC6egGCLImh8j8sf4gs+2xdGKXh9mnW8BrqZJvQPkeR4D";
+ sout << "Fro5V/EFe7EAIXpQfMRoNpHUSyn5oPJDFYMjjc1EEO4C6qqJ29nV149m60BjWDuVK1y+mdkCvaDo";
+ sout << "iZfAKI4TiDExfMpdAJM5Ti6G7pauQnW/lxGNX44JOR82strVKwsQxSecUc+uT+kYjcdV9Mx29qJC";
+ sout << "qXJgi2cUhrNsVH0LIe45X3pSzfFnMQ2o+fGAURgQCSW6wToqmtHBsCorr0v32ew524X6tZz11HMC";
+ sout << "7DKppzWxGTBOCBwOPrAjwlUb8zaRpj3bQGXWkvDk7E7ZUMQ6TJu0wgkuBNIPeIAh2tLfGqrqZqxp";
+ sout << "Y2hM/G/qQG+Bukj8yyxitXqIwceSp3v2BnLnL/WriBpSVEm9LnjiPou/BL98WMhp13UKWe3L3XkC";
+ sout << "izri1YMoCyxaQFX6RODu4We1vi/9gjamFSCAc5Tj+CmUasCJpbmkjt7Fp+v3PhXa4qpt32ZR0yuF";
+ sout << "G0dowpb8WYvT3U7nWAOFKBRgj9Ri6QPlCVaUa/LnkjZ+fNzytlkzQ9TTsPpOkEeJo+nCF3cCUYBH";
+ sout << "Y6lIyjcQRk9guLIgk955mBLpyjni8ZFOOsjTsW+LoOvAiZhVTGwA75/g5z6IcYLlcb0nwpZ/O2fS";
+ sout << "QPFcb5V6uhi5TnQHDQGHihSU4MBo5BQfNd+VuSxliK/TVvFU0yYjqPzKxCxgBpDO8qKsPMbc2YKL";
+ sout << "SFY2ygJ7PwksSIEQUum0MSEFf1ZJ3WNTajxSvFLToOkAtLpnvZlWymYkI72/Dgi7jBpfhIw1U1Td";
+ sout << "tuTLc0L6IfALX2I2VL2tOhBcisUL8IRhDipxhBTRBaJYLG2RB6ICKBuAQaXf4ODAPKbLhzfRSss+";
+ sout << "2VTojSwerCyQkKyoUZLR67G2ysWWLERwD1btSNH4IjaPYVEmaWk4I4F1YZhrmN3q5du7t7g3E4C4";
+ sout << "/UVLrCVTQD0CnBVBB5hzMEByG/4ZhIu+JWx+jRx1288XA1k84c28NLfMnqDsLHGtVxOLFDBgwFxs";
+ sout << "vD8S2E1+G4La3DQWc/X6jfkC+dtp0ihh5qQxGaGCKh0mcd3BHnNJYUSqSRQLRhOjiZBxmujGrhJG";
+ sout << "oHPaUCxfgY3vl9y6KAVlcLcKTYZpmukkjxCEVOClOy2pHYivhgkO2HR7okgNGpj8qN9EcVTWPq8u";
+ sout << "dbBjHLQ2GbqHamyaDJFUhJfsibyXR5ZtG2WAZDH3uXlL8AGNriBhwgGVcaRGH4sO/NmWWdM/gnap";
+ sout << "6geVpginIZALN+egxDTQtxTH5qTPfkMg9tdjlX/zB7e1LbVR40waeP5PtanIvb7VU/GbVbQMEDKc";
+ sout << "Lqfj3v6RyK6wX7mDvF7HWFtav8R/j9wlgf75kOiXz+2eN7GeXEmF68LqH6g4n7Ulyhq3uqszT4Jg";
+ sout << "hk7ynKJoLURg5KyJPTUCvadDaiqaLH4hF2bErrQzIIbbKDCq5Cb7n0EhCZ03MjLFs9+HSa3yfaGN";
+ sout << "NUS3wdGiM9x6rNaKDP6/vySXZzBvgtinskFBvb7UqCwmQ2MF1lwr0+nTNfH7R9fw3fi+tHXB6kyh";
+ sout << "PovdaPH+3dfnsbqVSoJLj2OvjsFfTFQXn35xd/IW3UEdBYVSDZP8VGRnXQUSS4BbJ79VUMNOTmwz";
+ sout << "CsoiZzIZNgHShekR2XKv1oXM+BheSAxK+r/d+VdPgjlkByfCwuw8iP/odUoaXzk6iTh8h1pGyESL";
+ sout << "QY8mNIzzPsU39opNlK7JmOzlYG2wtCS+DcG+bw4HLJP3Or9mChHpN+V3xzL5Tsb/5fGeqcQ0hvsA";
+ sout << "aXMhlsnRtxRSDkfE0s1HW0r/O63X5Hm1Yw/vJw8BzEtNYg8h3x7xvECS4vAwwuKLS30rjlVqjPqI";
+ sout << "TNchzWOA98U8AoC3t0asTAaEXce8tPtLqXD0EyycoU3slyfpErU4vySzpCXtkv3BShevfZy9yhX0";
+ sout << "2HG5zTc+l8GdXayf6mVSXaQ2N2OV6gCwd+hwqHjqvYSg4a0Ug+/cEw3zVi5AGiLIzTGDGsfJHE86";
+ sout << "9ohKS4z7yI+doqegx0f7N95Njw315nKSZnSSf6Pa/I20SrcQabMC36H2vdv9gkOlsYlZLyCOL54P";
+ sout << "ZOXlim7GgCt8LPEO6maHmQn0f5mtJAYIxMrJKoMasXvc2ZI2tktbh6bAJNfpSL0KbTfeQtaFJnVX";
+ sout << "C2f8RXf61VY9rNVd+qtpNuiavf8ZuaVbSLsLzF/beAFpS4djI0Nn78CJBhZAnzhPD76byg/vXG42";
+ sout << "nyD/u/FLJ3eccPnvs5umbz/gPiFk6gW+HnTXaYEdwaGWDdlr4QxvDki8Wsr0AWPlzA8D0nmkPCZW";
+ sout << "EZLBUIUjnBN2K86dyqEDW8+C42vuwXfa31wkOX0/8S7FSuT1BET8HdK8fykJ8NxdKlUsIFNr9SPz";
+ sout << "maMVyvkPp6IQ+DG9PBOFIaFy+zHbPzCRNNd3LTBhkQ0K6bP7u4tG6b4fdmmQzSSGsfXqEUiXkjGX";
+ sout << "ge14Qh+f/2KA4TjBZDQWF5NKR6/x4lsHfj8dZDg3+fEwY2fqezjD/jptis7N/VfeSIM/3xD+gF3w";
+ sout << "BqJn4Wz+ohlWucLfS0JRREnPAWfje7RQYatBkLok2Uy2hO7lgfw6ipUHNVPUw6XmK3VW+McnK0Ur";
+ sout << "L4CI9LAFF+kDdBfTs8hnhmLtk6h2Sucjo1ahEBxAyUuRgqMko5Sy8Lr9Eo49KiKO+V8LpA5ZDMq8";
+ sout << "iabdyb1WLFnyvE01K4uKqGHLoeh7heD7/0sAbIVySks0mv5cH46AT288mIVcHrSUurhtxawYZY4P";
+ sout << "/DqW0jHbqIkZWJiOquIfeTbtgRax76gX01JSeEdL0UyPHTmoqkvMdQVwjYcIBdLrCPPWQWNjkmWa";
+ sout << "XBedBCzwmp6fZX8ew5AABNCmlBBlhqNFZQ4yG91NXuiDoS25xckthn+6l7Mn0FHs9418wKqa+3eB";
+ sout << "uGqiAJVwpgWx7CWhWi9MonFdA1nni9AyjubzEaUSbzjL4ghneOGC38FyEQcuKIxrqgY+ManAAdlc";
+ sout << "hVaHl9Rx4r16AITagHNPLwCbbeJ7nbM+arjvU6qmK4Bg4E96IDjrrp2EQJMYZrs5+oRbpdtomWTx";
+ sout << "k3hcUFCMUiulWQs/pc5bXm+Xvx0mNnpu9A4GtFMzzpKO4M9Q/mtKch9H547N8hjV4jrWsJCqplho";
+ sout << "XIp9yBwPKVaEwWYpFcmpfQIJW+I56ewA0xthRBdqqqQSoS3zMJwdQEUm+XibYA9XALC2dkbTH2fo";
+ sout << "H9a4ImxxquSZZpoqUuRsbsgejD2v0ynbipTQ/lNVwswk18Wma+Whg4sOdCSQIMns2QW/3quqHoqb";
+ sout << "DC06jJZuQJnLNly7x48Pcus1gsWc6aVhbpl7cCLq/YUY0ACMS5toED6q+5mqakCg69pK4dm9WHIf";
+ sout << "D0hRK0v/05LheyllMYmQhO98Z0Jz8IJQQsl2sZahUr4Q8oTTFt9rLRKd+onL5HwdJQDAiYB/fex0";
+ sout << "3MHYPjyzK2aH6mN7qOG2VquMGb6LmOPszLSggrzFsVzPqYrzqH/6sGZPV1wMduWw/qYadGPlpzu/";
+ sout << "XIgnQ2Qzb21xqwTnivx30xgWDf8kuQWDdECGT+/GPAqNx1P9RGLru+tSPe06oZ8RuoSs64zDqJ3E";
+ sout << "KMmOeFAt+xQFBg6dEBs1pgfO78AfZDAbadYzvPCEp2zGGeYwhZlF+a+QIbFCyLe4EO6a0wlrPEBn";
+ sout << "3DESwdT7ETielqoEQvKdeSQiks0UGvlXRhxKdH+ylQslmdolzE57pMkquAwiFMXddLGFegrctP9s";
+ sout << "tmsvLPKWDIqiHy+F79eU6vOfwwS7btaRg5zuRKWkQ+B2CU8F/kx4FR4ZxhK8fzGjMUyjAmHZhEXf";
+ sout << "kvnchtB6z0pN7wUf0n+Clxo0DiXlJlRQPo3pZDttbC685azJ3OoH04xS37vxUSx1ir/LWLz/tjkW";
+ sout << "iFYq3qxftzK+jU7XzDx2nif7ZLc/+ecfHdQPXK4YZzJ1x8C7SvC7rBLRxnKqTYgv2bL9G1sCU+x6";
+ sout << "0hQtMba3x42k//w4RtV2KkazHoMTZc9UuNSsaSoAoGauzw0cs99op7HCpOgoyRu5JeY+fimo2H5C";
+ sout << "cXBecQbQdUB0uVxxEQHPwJN7vi94JfbpdnIMLLRjBwRs/2FOmMWbWWcShUYoWDSmJOLaw3Piwtk6";
+ sout << "bg/ppKqGAfrzDJkR0n1OZgKvUbnb8WRyZse0W+tO+PcsL1wvwG+8mMJU+AOBs1P/iVLxW/Y4CuXi";
+ sout << "/e7SckKJ3vsm/pQawrzhDIjOwofxzBWQ4kODfSEWHZvpQD0HNf/qP6IYfqhUu/0JtRJGLhlQ8hQJ";
+ sout << "iJBGtwsCRJWKrBgu6cizrYcA664+XPgjF/FQYLGmPiPrBdrbWjVxSk3tEOgVFOuK+bkI0EX3p0hm";
+ sout << "gYbr3oIec4bKzrSgYsIQtHMo1FnQl1xwHL0vH24KF6V6eyYpgVBfg42MNDk/aaCZ4XVIgH0H0wns";
+ sout << "sRXftElLUVk8yLhqq9kXBmgHvPZMfA5WTP+KhXFRbfxw0A2nWGbztsniRcoA3N0pGdqwDyOE5VGg";
+ sout << "tX94o9eS0eOJzh80SKaHFaX8GtlpVhogNJiMVlzwVoNJASK2Pr7Yp8uIqcUT7+e0VtkdsVlG5wv8";
+ sout << "WLEbqmRXrsKLs9f1p23SelLo78kI9nBujEvDSOCChnNwqNPG85kiz24jL0LMaWHAHlnY6uZypDyM";
+ sout << "TUmjsyosdrCobZRnQFf4UwUhuNtj3f6sQke+GQhzr474hTpfSDqLGMW6IcE3OcU4x3waC87DPSRC";
+ sout << "7PtmJ/+8nWIElEbGJtjS+rL+Ue6faqpkh+dkPC5ZsWHHRvXzyuRNawC15L0kLhhCc9Y+s+fWOppC";
+ sout << "iWtPPQKk4PKDA/g5TRA+KPkFH0B6YchdiEaCMLmleDqF9uo+XNzMnHdOKrkTZ29gPosM9w8CpTSF";
+ sout << "neDroZT/v1ckXkEZ6rhlVkF2pBmqG0DTL3LPclzO3JC6i6noY+kFU0jSARjXgQU3NXrYpgeRhLuv";
+ sout << "hKlC4Fl4xTK8l+p8J8Uk9zKTKsAdyDcAT6rBGfRpmJiN5a+lxuiBSCyygeHDQGhaJFROD53Q/m9M";
+ sout << "dxBlTjqMI7r5M2BNFKaZ4vhFdukvCbu2dPm8t10pc4brs7L5TeBVo5qxaFgRbkpS1mTCoDtFH4fi";
+ sout << "Wl+zpEdF6VpKrmFaCSSduE2tMhr164re7m4P7CxeJWvYdFfWGD+uDhFM7oPVXvvkC5gYmjdAPIYq";
+ sout << "co6IvSMraA9ANQd8b/hO6u+zo+U2Fos9Xe/1u5YWr9JdXZ9oFsdNGQLaLH6VcRrwAyx7+tRjf5Ia";
+ sout << "IHli9+TQmZ4tbtxERYe8TaqFqugpCGtvmcE/DFo0BeWgFRFnAY6nyXGgJCrzbxrMdCOBdvIYzuuB";
+ sout << "+A68idNO9ifsfNxRalfJCQNymwy4MAylkG8ncZ6Bqx1XztI9ckbD7U7TBMHCWt9xnMxQz9G0HmsQ";
+ sout << "pIa0x8tKk5zZ2TyOVe1LjwBXzwhn17i67Ph+NTA2pw8La9KcI2xdlDtAhD+LxRBANo95CeGL9NKp";
+ sout << "cDjWMrqwRlvXL0qroKeJuRqtSPGC+hbFEJgTX7iWDq4QJCyvscIm/lWz0ZQIHyXyh3yV/UyGbMXD";
+ sout << "hc6mVp20J+AGPR0NCEN3mTh01ON3LJI1t1P6OT8oGM2ofce1YsHLdMlY3uu00ErXy0YF6vz7jft1";
+ sout << "0St41Ydx54E5As7cbimxngKnJsFVIdJC8uh8SaAJQJWtQK6DG5sXJVDADSIKXM0TuhRTxRREGQWB";
+ sout << "W6Hd2jP7ZArcBCuB2GGMw4sn8iAYMK1LP12hxoZsBZ8iAbohy3MpWZHiE9MDU5PbGRyNsEnuLmQp";
+ sout << "APmj5sFUcAsA0MSUYZli2jB2WWAWwTaQ1CGm92tdrdflShh5FR8IhAZrwXPzI/w/1vAianD9yheA";
+ sout << "j0cYf/EaB92n9xRSK5zeajIV+DFT/451rNvi0Dqea6cDxRkza31G3d7pWwPkY6WiGdvSzlgy8uJN";
+ sout << "pt2gJoZJ6VzzeYD1bsb5X/FYBtYwFuiGicRbUadEA0b736fEC3AG2OZVh5bFmVArBoUukUoBNf8S";
+ sout << "gWgzfeYNyL25qa5jaeg+X8okmGtNUzfxLtmJiCY4/A9aDh3yoSCIHwH1we8m18DjMTXYzoc2b99i";
+ sout << "18h/UV7FF5xvl5awkZyLjDPPSDtdafb5ufHyNVjblORDSqS2soTzwyoyZm4PTCeiXWaO9Dpz81fM";
+ sout << "+bCkqFrXm7qEJqYSrCGLDlxwVZJeHm/lCNpbO+GYq6Cd5CuaJVactLLRre6s43nyD7IxiRfCmb/f";
+ sout << "LUyVi5sXEIaWiw80Me64uq/s9ADmuDUkX9Gd8WA+7fyyytSuMpooPNEsVBY9LE5nKWOlOy8Hrqmf";
+ sout << "piWc2Pf5nUtyZSsK3p94XbsysthhunMLsiv5j4mcs61xi2IyEgWB5hJ01qk4gQV/8SHPYJ4stRxA";
+ sout << "Ea80306xhLLKQjYSpPKHOvoil9kCHIgBzOp6lZas2vOzK/w50AVekKYXFQK2lWMs8TUBzWy5fYPK";
+ sout << "CZgcrWP0fShh9pthBw0DBEmpGM6fQZ5XQlBC2hG8HEDbbakqvIUkpuL7jlFde+HW31aTQRluTYl3";
+ sout << "huZ21u40SMx86ghv3VUzHpmF5x2b+UIIi+l0yg5FZHXRsth2xRsm4pNO6bspgiL/HrWMfsjwD2Vz";
+ sout << "d/2Kx2Dn9FLRUg/ASedunqth0Ovq3z9Qds7pH6QVdBUmtPokcHoC3KKl1gmY7/cN880Az+h0SMpn";
+ sout << "eqduvQM9adP2tmuybV5zgKGCt1q6cc0fPPBD1DuwAgr832VjU87nVOl13p4TV9NKX6wvnfRcw1bQ";
+ sout << "nJdFr911d2uMjwuPJdKusPo6o86c8YHTOcmUkC2QkMM6gsYp/lK+lv9fwJhvXUKg0aBlNceJ0/eK";
+ sout << "LGzHHzsVCweHXjlVY6Z89uMHZZeqp/wzEfatokYF+jIfD9rP+9AyuMIRuIOuXTCkemsGcAHqpg3F";
+ sout << "EcSZcaimDAyropuc7CYsVhhxKRDQBYjTbnd0dhIIDZ9WVP/MbG7QRmJF77TB1+a6GlNjoOYEuJfm";
+ sout << "RX34p0IQ/ycmc8PcUbFXAC2/epoQKPRprwg2+EbciWSYQe9i8T9gzJVuVHaWF1GjlsNJNvJDnWVW";
+ sout << "2ffDvQuZ/YZ//zqKcA6e9A6tTttCUD4XebQmhT5vIesFMuKNUHBvJZwerszeY+AY1Hs8kwTJNMB/";
+ sout << "DDj71I1sz1vq7X8OczT4vaHqLDg/4MiyHFatIaGMlbegVLtthaj7BdhwxM7xz0iilKncYQ2zYw9S";
+ sout << "wMgYGoTth7eZQe/q0rgzXi25acEvNkbidVbeI+PtUQ1694G/eKRqOYnmaWmhMsCsEUJH5ZI+XhkN";
+ sout << "+94T9Tjb6s/P9z0PisH0UAUDT0Rp+DeikJF1h/yLnxhQ3KxIwt9yB+ZlizVXB+6F7xcOAXuVocD+";
+ sout << "AyoxOZRmI7dRlFB28ki5Bcl/EHXa70EEFyFao+xc66nv7luVhyscR7PydzdbIlYba2tnkr/QS5RC";
+ sout << "kQ+4t8Z2smt7YKo2d/A4Gz3YNk3K3ZbUDWWSClHkcUklQVJDGg4b2da+V9RV8iAuugNuEdDVrs1r";
+ sout << "ixGKhyyEGGfIaFUPEaL5/NrAZqBuX6FSuloE7m/MShmkxRuilG5Ngqy9Gb273F5O5x5T6/koSaTc";
+ sout << "5tLEdNFmpZYmj7vdIAsHeoyjxmmSycfE8lsCFh1yZRp3I58aXVxBoTHGnQYkQoIeBpr9GBPTo9hx";
+ sout << "k05R5M/LAy+Y11NSEW/gRNSiDkmUDGclorU8nz+dLVuyq4ZFX0fGt+IH92B/Ut6oX+S8CaL0iDcf";
+ sout << "L+AtFn+m7o5UUKZx9KN2YEv3EbxEdl3m3BsSsgJr/KnVvd88zCEoILj6zZAHE0tkqrYRDX0rKjGc";
+ sout << "1LNaJQ+TGXjE0btPlj4hVLWwZHJx9JT70uDDDQ/xz4v8p4Q8MQqfyhf5dc6/GeZtMP031eq1R84J";
+ sout << "TeEyGjpF7F4Kngzg1q8mFT8Ay4dmF1rCwvwMl7QGwMAIp0lx+MRC3J9YK5TALpvK2NA70LNDzquo";
+ sout << "vuu2cNlAGDtCBJNQ7n9vFEDy37OeXwbTpoJDOWXx4uDL6HQD4yZKxeFbX9AdyS3pTcl12wDkodRU";
+ sout << "ESXKNoL9DydL+atZpSrTK06OYqoo4s5ihsGUh/CRJe1owWDoCHJEmT4ghhVeU8YVHxxdVEpOtXw2";
+ sout << "csBk3ljCjfpZoXf5yLtEa5Md5JdAP7fVuqDv8sPzg/I0IvXvD24a1RxPcalo5Z5adVfWWGZkC1W/";
+ sout << "oBAEgcYFTCVW7IprKK/JuNv1988z19JHhpqMEDNWr7JszAEQ9KRTNtLYjFb/uDCdUSgqiQbV6tjD";
+ sout << "PeeKTQbxZ4r6fmtEuV75z/0be62g4t+/aHGNWJjJuZ0P1A6of0LOPZwKhRY2kydC8okBVp3TsM76";
+ sout << "9p8yuQAs3WuzaSJR8H2woYQoykHJV/ARapMBuxHlvrhDWFITpyN2LXl5suea3UK1GBJ6HWSiFrIQ";
+ sout << "RvMpY13CsRH7uPdx0svXicHK/GRnOPr6ei7cmMsp+nOKXmE15XfatnD8N6OHLImCrfY+bLS1FO4K";
+ sout << "EOWti+cmcfz06z70BNUnGSHJqWNohvvGVsre5rimgFSRUJrxN1RTrievQuaVB+hya9rL+dKBRjmf";
+ sout << "Uc95nLFFBzuhO/CYEzaGX8JpyyQgh0I38lMww3jK+FRbw3AocP7/rdaNpqi6coY/eFrl8Iv8drWh";
+ sout << "5B59c5boqoOa6ZFvIkqB3oJp7ogpO6zFnSS3rGXt0tMWyj5PkSWeN2Tq9pO2gdSM/p0UgN4Ywcpn";
+ sout << "rU8gtJgD/zct8G5pH4rAETV3vjfKEnlqG47oIDJzi2PY5zuiSlf3z5pY2nnPjhAFhlBAOGxCV+Ch";
+ sout << "i0Y0ziAO3PKo9YXNF8q2hnzroT2o/GXjOZdC56mkRdzYALMv5vkPTQMBqddjahpZDVJLN/jCsnGF";
+ sout << "fVOCW57+dzaFVT5Zlsk9xqIaUim+bDg2IHv832FM49MIQx7sJAS4lRmsZNlS1NjWKHwsOtgLPK7+";
+ sout << "jRIc6qhU1i7l7cWFd6+oM0U3Sv5yBXTLdTGbWbUniUCn0Izv29BjX9KouaFPRNTyKYfNnoE2dDq/";
+ sout << "jNGe+Uxcnbt8vxewpCqRvS7iGBX+Ylf6MW+HkhFu5eKu2pSEK5JyLLS/+kSRHyLhdmhz1PBRh+mr";
+ sout << "duozCqvGZN1cMESXzPAVSgKE2sFz7au28raq7YvYI+Pe/8AbD75HPkYlEdVu6SXzwNGrCksJuE1A";
+ sout << "u/tAl4GZzEzvyQqUtcf3HD1dWV/ihrtPgXbpCR+GeR9zWrj4MjTDm7ZtsL2NDm599UTNNPJgaIxD";
+ sout << "5coKin30t2hOg6LzFoGKpAwGTijauINY/xAqgQBA8vEQ7uYGK2bkPn9llAAG9e2L+KPKVS6nLyFf";
+ sout << "unzr/rPkxU4VITFN6V9GGZoJQZ/QFiCm6kLO+beLPgsPkZAqJNO5Gl9OTa6728Ew05ZnziMsWJaM";
+ sout << "OaAqjBrE92wtFITs3Qdr+CHKgKqsrGXEUK6hfylB0pOhtNq78gtwsQ8rFzwyu3hoDv4YVEt6FBOx";
+ sout << "zb1KBFOMz2x/RZ1qTdO9bMONUe31rjsOTmiFu8/CQyYfjciF8cp367jbzgcWV2aFhQkY2tA7SL/P";
+ sout << "HCU5bSb4qpqJG4zg+RPv2Hx/6DpmIDXwJgSajh3a7O+HfcMKIRvWOXqKkc4LPK1RmMy8aDYzNnav";
+ sout << "frd4Ii8a2KCeVqsGmJylpypEeMyjQCX8CcIYBYOEVQmUQGAoO71Cauftv1pt1yFAUzpDn+gGGSmN";
+ sout << "pp2ZCm/qPb63lb6Kz94Piq6oVw23zqFrr0pqXr2TEi4e7jTLzMGCcXBUj/qNiCly7TmlFzM4obpO";
+ sout << "1ev0yo6ccmAF8H4BOeyX7lqeqlwZHmpjc/8oa7QwuQnBXB7c7HHm+L9F3N9QoPnEqLtSmrJmNPoL";
+ sout << "qk1d0l1174BQPBZCl6dcCHQdefAZAQ5v66WcPAoZNlt0lVL6CBman1pk5p0e4zU1EPrqYIUxzfBG";
+ sout << "mLv2zWim3OpVjpYpB82fhtIlyIwOst+2rkbeCdIm/3X54LiC/hudzp7zUa4pe99DM8jenauzTIR6";
+ sout << "BdqYbHBRQTc5rKaUmRDq/+JPVaG2dAjWVTdPHLs+rFM3MvLdd0wPG2T26uwwQyhAx+PHT9JEhU+t";
+ sout << "pSJpE/s6LlZmqt6RPuGgYuO6jifhECGWmdy6SgT2wYl/9REvPSsMIMiB9DAbdKAFv7ios1KtcjOq";
+ sout << "pIOUs4NKeJ3QMSU3lE5JXf0V45VBkJ5JfO9lyCMgHRGFd89mRf8/HON8GYkSidyFF+d2Z+po7tHS";
+ sout << "Bhfq86T6T4vTUDE3KCIcsir6kE+hyZylWw+fnBRzWYVYMBp2YCKHybxBKdkxpvAnDLibZYdyEtd/";
+ sout << "20RPeXxxk54lJkFAjNy6vtnh6vLomfNALcZ8oqS8iZWX5v4q35b152XHo9lEWbTxokbbXeMmqLdL";
+ sout << "UjBrCPkD1j9ogboDfWD5TNg60dJVikPCyUHbTSTTEU+I9niREiVDdZToXbeaeRgOKYxtnwWiA/FM";
+ sout << "BYXiPb57y+/il8TD1ZT74JRjz6kAmSa3bM7GClr//V3Mdl3TpoP949ZhX1L16IHc8WwgE0rQnQHV";
+ sout << "NxPxVWS0EhAdmlYB73ib5jPua1rtlwRbeYbDF2iNsuw8ss8phioK+ZR6BnZX0XZN2Tw58Fa1e5kV";
+ sout << "y2kHZGIkY6hk/lrA/vAP+QuV8Pxb/P7VXVsgkHglBYuZkkZLgjqAZDvPjvZcBqEDQjCHrG6V4woD";
+ sout << "X7xWGVYXVRt5vJcwOX0hKCcUSv3+1XL6+ID0urNTuFqMw96QKtb3//H6qZvZIO/bYGjJcDVbQHJB";
+ sout << "6Q//OjqKgSiw67SotBAvIVQrgDeHUzaS7JdjyvWHCooClKrAiIVcnKX02r1y+mVpeL36166MC9D7";
+ sout << "dAi/coCiOwcQ6STbBY2PPhWrko31E8o/l3uDeC4cl3TIVjkFjS61GMogqvd2ISZ3Egq1jZkRYMln";
+ sout << "962j1y32UizRikxEK+2d0UREZ70oZzW3UoD6YqshoElP78GkH7HGS8hjpL+UhuCjCura1FK4/qVG";
+ sout << "yp5GneObh4S9DzJV+IZuviLd6drknWn+nKYS4YPWkbOqBu7RBvh3eb4bQMzvVl2thL1b4Ff8Q79d";
+ sout << "mWxu8ajtptUs0OrSor9gnqrLu3K3RWRTWSElrrMHjCD5GZcsrR/qp7Ip4GDBRPCVJNLa1Tmm8TMc";
+ sout << "kTkGtbN0E96kT2qVA4/s0vYCxntAUPunP0k/JtWg5YzVXQi5/hKDdIE3EfpV2PXjveDoBasXAmEi";
+ sout << "6oUcZk1zKqwFygj1793MM02voesHS7BxWz50W6yD+SozDsnliV7fY4S9+8vj8CipRYSD8t7MoczJ";
+ sout << "hg2tEMYVVBo/nV/4l607tvicVT8HYWOkBhuOgeMNrocTp/3zcfiCODeda8rzbGPWjmKOCPcgOmTD";
+ sout << "TO5jx0f568jqAuhFgeg6wv/3uXuY3mmFGWsCx4Sf+2nlWqhCMKmSsRT84UXcFYpp0Kcvx1OUFC/c";
+ sout << "E64GAqCYYhzb3hF7jys36qQefbfm9+t3owVhP0d9udWNBzw/QeMJ6djmHvk11Tl3qvjGUGV0iXh6";
+ sout << "4ZxyCeLQWZA6cNcN8Ovd2vRrtQ8SHlFPhMKqoevmMLkyZKMrD9CUPHmgzlpTuAasa7PEnbaAFHcO";
+ sout << "sVE1KNm7uMU7QjFI8u10VRJ6qBpTx6Z3GXPq7Jslk2V6z0xmH/elkzMAu2Wr3MId0/7GCuheVZhh";
+ sout << "VAf9EWJ2ZfZxGBOXd8Io9eiatd/VdlOh7FBglIGSpx8UHU3jzpSu1fcnCjVRg3XxWmUI0iRrqxQc";
+ sout << "iVT6ttiezDImpPlHxP2OjgIghWD6EZ2Gesunu93a2lep85rEZqN8sACV2sXDy5K7CySNLyhNE7fX";
+ sout << "eV1bU3FdOstad/82yh7TJdIpIdFV1tEOV+gAOMZa+516EjdnDs4WJpfWHPWG6xdVJWAvCHss1B8s";
+ sout << "k11txpDa6vs3+NCx/mF/6ElB7TxkisPo1m+KfgjBGpI/YHlm6c216WwSh1k1hLk0T3s4wFEb8M5w";
+ sout << "BlbxPkt89Y0wWwc/Eg37XquMIme6aBZjU3CZK1NwiAPkKXa9Y6fBTZWLT3W/NpP2Vk8KGxae2fRo";
+ sout << "F83VOgFxb1SUIePgZ2vMS/6OnuRxNqiwkcDEI15uVcK+l1AynHFqODaA31sxqQuHnw/FOrPG5yJR";
+ sout << "OvmgJOJ9ss9QZkvXaTZFc3vfEZElcKdW9K5xEZfiymZWX9Qihiv4PG/L+qo5Tm6cFxi/8MVW7Tgd";
+ sout << "OV5whxO+RWOCj1kyuILneXxrwiYL3tn74Z4+tT6oP2I9l2UXF574JXrOzLLeBhULrD9fpPFlb/lM";
+ sout << "5YfP97MRad6MEZfY5uMUa36kUR8s7FMdTpSyKqhEmzmepGD7JI0uGPNutfSDO5SJsPfK8Yh1uPWA";
+ sout << "5J5d/NEUp/fqvoniWgm/2ye0ApW90EtX9eDE/DyfPQimpqOdFBO7/EvDkDHlZ0u08F7+sCavgzxE";
+ sout << "jHMXJ+uOF5q96vNnGDhyc8WC9NRzX66GChvTCh7nDhBYLMCZzSvWU7wPWC9OLOCvA+lyTTGvFCgs";
+ sout << "qCrk5Hoc5etEIrpyOCe6evI681jAoNI0KK4Opb/vqVtKgLTxJhBbi/EVhJTzdALEB/WduuYpfqqD";
+ sout << "sUbdDlNRdSGgricRZUxD0iN5GZUBDEzVzp6moEW+Q7NxsryW6/88Ow3ky1fm41QPwQ40Rk45cnIU";
+ sout << "5nZxTrYUkBoaWR/Lh43XtKDh3cBhADGiaMIPBVJL/tOUtXTCj93ca73/LqanFOO/rrnROhXUCn1h";
+ sout << "+LWEWn553i9PF0CqFkFjtK/dP68wPQ7y09/NYYw9P86YdgoWwm6ZlqskD2ByyYgR5KimmyJLQyxb";
+ sout << "CmITcgVbucDiDxUUFG4Rq9Sgn4PW6jGaoujCgclaxOgLnM7lqREfW8XlN/yH8Pvyt7hjAIWNOHyg";
+ sout << "hiscgSb1ev+btDSm+aRCjPgRNfBDApl2zINR7ey0wA+wOl6wZh7cxYwbeb55/UqH6OzEXbjJzjki";
+ sout << "6c9Z95PGsu8U+FaBJmWyJWqb/SxBxsf4zPH154KF7wE6b0AoP2Y1tGD2hDN8WdEthVWbztLm66nI";
+ sout << "n0fz38pv7CNJCuVf+jeqvk6bh8/dI0hVF0CsMd5uVe+fOLzK3nmIma5nB/TQvcCqfR1YjDGV3mhd";
+ sout << "QPQ1a7ypy6WplKOU5LamJw8IaYrik3Gg2tLo63FfE8njUkrYdtqiYpgk+okF8vF4S8c8NdWlgTNn";
+ sout << "KE+9+dPQZr174KhRz1JwzspIUqW/d/QjGIgJm5NcXAo07/hgpfI2zfHlkGP5ETxLnquzkCcCsrnK";
+ sout << "IQ+vacYRwHRVSTVWpvQiDXaNK7RJrfW2ei23/bW8YkE72+lZIACjehXSDgKiBg0EIStpOVLwTSln";
+ sout << "fXVW5fHQkyAc4fOVX6bGqcBu40hHN/LRFJY7Jv5qS/AjCtLUR4UCRhMWAo7ITDLgbXoIDKnyrRLF";
+ sout << "vS7LGaJ9IHbFv0Lw8Xiqr1YSpjnLZZDcREIsjCf+2G/7kNBY96DPmp63sGuBfIR0f/I6MzUi8HNG";
+ sout << "R+EBmcCO0AfPzTeoGkIM9+5YmMpXwvMU0zCz71PxeLlnTUVUggnXTBAa92YS6HuhGKIl5aU0OCXW";
+ sout << "76CfhWijfNZCG33EdpOJbXxbtbX97y+Xjn1KyPnNW/Wyk5VO8lqD2ZGC1Wnohpx4q2VtDkVzw9h+";
+ sout << "DDbj2hpyfv2byvYJPUSlZ4bJ77aCkYuZsjMOaz4MYjVfgdi7svHdnIBauBgv+rubJAwx8oB9bk3K";
+ sout << "Wy2EDPfLHGxtUKt9+keHGnx9xZ9vGjLXzaLiGltRQ5YDiVK/vXPUc8eKy7p+NyNu80yopPIjJcgV";
+ sout << "IC0mPwR2BvdGVweS/iLAuMVJw3STNQyl7XVej6lppzt2SWidtjqxYnYjJwRYNnFr0l7SgVA9Tink";
+ sout << "jZz7M4OGdDN521PxFXjOcRRRM1Kr7/56n+VF+LdTRCihmUsOuGi4bBlZ+eKTcUmg7FX6LXKptWLm";
+ sout << "h6QUA5ZXcUZ9XUrJb1AxaHmfP/XXd9r1bsi+F3JdFUPuCOZHrzok6cshx+9r8WH1MNCBBVTeUrFl";
+ sout << "+65D1RufbIVoqZfQ8l3+zghe+U/ujnqEox8ysQAZkhYG6beS6ksj/QhWbGno9W8TeaXr2NvcF2ct";
+ sout << "PAh85hlFNWcxBdGnHXl8fQJ+p5+t8+jftQLoVqd6B9/beAUgp9KYrLugImLUnzw6Q7PjXCiFmo8d";
+ sout << "gqPvKtiqj4mKu5L5L4/ul2zdN4zQtRE6tm24+ENVyfJ00adWwqEGxrCIvUMiNbOzSI9TtoTVrKgx";
+ sout << "lON3nzfcVy3ucT93AtQfa2reu/HwRVNhn0GP/xZGBCy746if7jr5Fa34dAESoJ1mlelIKOion8QJ";
+ sout << "bsgQixF1UWwd1/O4DgHG+U43HYhLWOSw+NOnajpEaVoKB+jf/M0u5+BQvbwCcE6zd+Vhmhzy6x7i";
+ sout << "5ySbdBren80S4wUt97VFIq7HI0KvvWpkbAeQjGOhAWIqRrtbJup9yQa09VJiR0hiMQ8K2UlTx3By";
+ sout << "BFtRAiJO5mn85Q0YxqyogwSE2Kf4F7qu3EBnT/rEta+a0e/UcElFcZPpJfqSwS18mNBPDEyagvBv";
+ sout << "BQiEumckYIVwtFMpfrvELupxCTY51anDR44j+RTJlQMf91CHDZi9eewt9Rfo4ja5HTTdK5Wmjkvt";
+ sout << "DR2SBS/Z4YJX4elAbie5bsrFWR7IH9M8M/vtR++6Sw2SKEAQjS7D23xmoKXD/bC9JWoz9P0yICkJ";
+ sout << "Ckdwh6H+FNzh6Ms8qlcEWtQD28SI271I9tt0Yiw7FvwIYH/+aG7+PnXpyei7Y8OmV2scS2CaAR2e";
+ sout << "+k0qUumoXI/yPunLeJE8BQHjslaw8eglGnb7YjfgmoGPC3lzrc69UX3Okmnb8JJUoC3KEsN0Zf0n";
+ sout << "GPErNUSm7ABFRAQvHvTiDxfGyf8aN6UNYZDC0rNO5MgYpQxvmeTnCMtXz0P9OEpaBs3ZuNoJVR+n";
+ sout << "s1zhiz5JteC9VmCFM8PknTz2tQXBWonqXdHxCPOIi7k0K1Jn8ddygrfUczXeMeZY/H/akoWADYHT";
+ sout << "cGPqpi/81wQUaE4GmV6X27XcuHUcELZTkyTqpkBprMoPJJDspnbFj0aaHiz19Ws0weE3wWhUFiA4";
+ sout << "D4WlUi4uF40OEAhnv0qcSVHil71C7AEpTcS1dxe+GSs02PppfT+PZDexeWk/S/C8E+O/Fr4BVfO0";
+ sout << "G+M+XdcvagPHLZYLTEJhLhvQzPQRbOb9vdPUhiIsodTUzejdQ+zA6k7ynQqNEDAaVwyy82AQRyoi";
+ sout << "4BFGQzQ2hYCUp+In9B/69qyBSvT+q6E1YDUARctcr3h/AR/3J7uG4VdxhFA6YOKAnJGCSCMdunwi";
+ sout << "hb1or9pPHhW5rDfvmtH9iZCsuvvJmFA8FXmAURRDRziSxYR/zcApR0JBT63mtyw3lMCHP1qDg95w";
+ sout << "0ysG3hLdyMI3lnM/g1W0tg1hvXR0C3qjivvuthJHyt3fqSZbVnvNEkD2k+7BoG6KWk5EpoSqv+Ni";
+ sout << "znQvLFggfPOtd6Y8BkmBcNhCTCcyMa2ZkvzUNO7419VR/gNeU56athpUvD21r8d0/MWrEi2yKWsM";
+ sout << "aCVwYr/eAgp9kpn9i8RuSJmxe4NTb7Isqn25vOfUeUY17vS+c6wjCDqbkmukld4nOHl8uHlHdJoK";
+ sout << "elhC/yXSgUyOM8yKFSyw+Ap6v9CISYh3y09g6gBL35LjS7Vb4Ew/ks2t2L9zWrU+IC4BLcQDmMfG";
+ sout << "QUk5tt1n05bmuLmnSboYhPj2MNT9/EiqHY9AfwPhMYmWbcSCshdShSoYs1aciC1gc1H393KbvaTl";
+ sout << "N6TeDKz6bEkvM0mOu+wRDR5u+tnr0wWSW8JkMt+WkjPvqWkGYiKZuhJT/4rTPRhJEKXE34gxeyFA";
+ sout << "16oufb8W9C8Fj30WPJq1bd43y/r0Fs1dwOyZAyLsHv/2AtO5/Jw2KEHsTIgolGr0Qe6//jc/c50R";
+ sout << "TN/aDVTBCbvhcRtV/zOuy7oqb+p0IM3p7eWtKFrZ1wXly7FvvPQ5ODn9CnG5wo59XTikanWOMLKf";
+ sout << "MwQt89ZW60v9bQTgIUnFYpVlp9SF2XPxmeW6x+NVCEOiXZQ8AM3nDiLA5M0ctrI2DzzLeHoEKWem";
+ sout << "TvVZ1MrwJ8jZoRsigx45HqoB353+bXlS+5vMB/M+zUEPu/HHuU5k8zqwU93NFkTR208ZtecG3IPs";
+ sout << "ENQd7J10XsbhbYhAvEkU9ZS/3FS7aK7bDvf7cqD/QcGCfIad4rk1Ks6nuGSeR7hUrH1NK1fe9lpY";
+ sout << "lNk3EaNPlBEBmNkbGpNIUcJ7ntUy+b1q+VoC+q300a4qo3gIOkN3s25NaDJime/eJmlRYZhH4ip8";
+ sout << "6+m+nA8as1/T0/4d7HXiFWQwZ49NZsSESry1yCs97C5IQ6nScahxHDi72AbQeNDB+RtGaQJiOUi7";
+ sout << "NSBNuSlm9G9GpR55HvMi/JUqF09BrOn+49zwYqMbSkf8CjoenLM7UzCoywGlk0nXSBsbANAz7D2B";
+ sout << "65qWXswtvr4xnCSfRLUNHs3AtlfEqpsdlaF9gDQm5Z4IhT1WOXbETcY5S8T/5DDBIoWi9rHnKuxM";
+ sout << "+zmu881jhj3d9p8fbcH65hevrYM49+ZQfWPXTMUY77YbwYTGmYgScAWmqaMugoMWD1ocpYYRM0IJ";
+ sout << "+SEiUb57moAOoEeiYZcPqmckTWuHJhYtgbuBojwXqaK/qvDssM/59aTMWagOYHcapC4gBG+s99No";
+ sout << "pOCnbe2brIm4+6xWs7LzSA38RZHZSdh66V3n+83R0/wAIw9+X35SXMwrXC96OqXF/6AFvqkL2Wnk";
+ sout << "SBbvyq0txWR6b7AaZ418Dmngg3yQh04fwc8xZLy7/1ZYAbGLRRV1mNrpc2Fa1kLjxoRHZMBA75Pt";
+ sout << "HirY4CHOvKaEdlk27BW2px1QCTCkZQ/gojWhiZ1kPUAUiW7VcyFSzjtXzswHEIAnGR2dWHgGZDVT";
+ sout << "OVuBJ0nTPs8itQ2Htelag60Et9jrwDZzYa4Rhy1FjngWN1S/QAp9iGe95SRVXuBtLNgAVp+sx7SU";
+ sout << "VOECSHoLfpSeZPvlm5ibeSN83gFbIG2rsTZ3IlvJjWq82Npzas6p9WVKTEPGS+Ux8nWIBT/enw7o";
+ sout << "7KX9phVWQqcYH5IB2waRO+Ke7h6/y696NQMq0R4Xbki9lmjoWNKFtM+GgLygVqxWWWp9iyQFkUQx";
+ sout << "7tRJT1da0ImlgCXS/uTTRxvcG9d/E5FMotFa6mA7py7P+eraScFdEHL4J0kA";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+
+
+
+}
+
+
+
+
+
diff --git a/ml/dlib/dlib/test/ranking.cpp b/ml/dlib/dlib/test/ranking.cpp
new file mode 100644
index 000000000..83f70d8cc
--- /dev/null
+++ b/ml/dlib/dlib/test/ranking.cpp
@@ -0,0 +1,485 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#include <dlib/svm.h>
+#include <dlib/rand.h>
+#include <dlib/dnn.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <map>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+
+ logger dlog("test.ranking");
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ void brute_force_count_ranking_inversions (
+ const std::vector<T>& x,
+ const std::vector<T>& y,
+ std::vector<unsigned long>& x_count,
+ std::vector<unsigned long>& y_count
+ )
+ {
+ x_count.assign(x.size(),0);
+ y_count.assign(y.size(),0);
+
+ for (unsigned long i = 0; i < x.size(); ++i)
+ {
+ for (unsigned long j = 0; j < y.size(); ++j)
+ {
+ if (x[i] <= y[j])
+ {
+ x_count[i]++;
+ y_count[j]++;
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_count_ranking_inversions()
+ {
+ print_spinner();
+ dlog << LINFO << "in test_count_ranking_inversions()";
+
+ dlib::rand rnd;
+ std::vector<int> x, y;
+ std::vector<unsigned long> x_count, y_count;
+ std::vector<unsigned long> x_count2, y_count2;
+ for (int iter = 0; iter < 5000; ++iter)
+ {
+ x.resize(rnd.get_random_32bit_number()%10);
+ y.resize(rnd.get_random_32bit_number()%10);
+ for (unsigned long i = 0; i < x.size(); ++i)
+ x[i] = ((int)rnd.get_random_32bit_number()%10) - 5;
+ for (unsigned long i = 0; i < y.size(); ++i)
+ y[i] = ((int)rnd.get_random_32bit_number()%10) - 5;
+
+ count_ranking_inversions(x, y, x_count, y_count);
+ brute_force_count_ranking_inversions(x, y, x_count2, y_count2);
+
+ DLIB_TEST(mat(x_count) == mat(x_count2));
+ DLIB_TEST(mat(y_count) == mat(y_count2));
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_prior_test()
+ {
+ print_spinner();
+ typedef matrix<double,3,1> sample_type;
+ typedef linear_kernel<sample_type> kernel_type;
+
+ svm_rank_trainer<kernel_type> trainer;
+
+ ranking_pair<sample_type> data;
+
+ sample_type samp;
+ samp = 0, 0, 1; data.relevant.push_back(samp);
+ samp = 0, 1, 0; data.nonrelevant.push_back(samp);
+
+ trainer.set_c(10);
+ decision_function<kernel_type> df = trainer.train(data);
+
+ trainer.set_prior(df);
+
+ data.relevant.clear();
+ data.nonrelevant.clear();
+ samp = 1, 0, 0; data.relevant.push_back(samp);
+ samp = 0, 1, 0; data.nonrelevant.push_back(samp);
+
+ df = trainer.train(data);
+
+ dlog << LINFO << trans(df.basis_vectors(0));
+ DLIB_TEST(df.basis_vectors(0)(0) > 0);
+ DLIB_TEST(df.basis_vectors(0)(1) < 0);
+ DLIB_TEST(df.basis_vectors(0)(2) > 0);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_prior_sparse_test()
+ {
+ print_spinner();
+ typedef std::map<unsigned long,double> sample_type;
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+
+ svm_rank_trainer<kernel_type> trainer;
+
+ ranking_pair<sample_type> data;
+
+ sample_type samp;
+ samp[0] = 1; data.relevant.push_back(samp); samp.clear();
+ samp[1] = 1; data.nonrelevant.push_back(samp); samp.clear();
+
+ trainer.set_c(10);
+ decision_function<kernel_type> df = trainer.train(data);
+
+ trainer.set_prior(df);
+
+ data.relevant.clear();
+ data.nonrelevant.clear();
+ samp[2] = 1; data.relevant.push_back(samp); samp.clear();
+ samp[1] = 1; data.nonrelevant.push_back(samp); samp.clear();
+
+ df = trainer.train(data);
+
+ matrix<double,0,1> w = sparse_to_dense(df.basis_vectors(0));
+ dlog << LINFO << trans(w);
+ DLIB_TEST(w(0) > 0.1);
+ DLIB_TEST(w(1) < -0.1);
+ DLIB_TEST(w(2) > 0.1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void dotest1()
+ {
+ print_spinner();
+ dlog << LINFO << "in dotest1()";
+
+ typedef matrix<double,4,1> sample_type;
+
+ typedef linear_kernel<sample_type> kernel_type;
+
+ svm_rank_trainer<kernel_type> trainer;
+
+
+ std::vector<ranking_pair<sample_type> > samples;
+
+ ranking_pair<sample_type> p;
+ sample_type samp;
+
+ samp = 0, 0, 0, 1; p.relevant.push_back(samp);
+ samp = 1, 0, 0, 0; p.nonrelevant.push_back(samp);
+ samples.push_back(p);
+
+ samp = 0, 0, 1, 0; p.relevant.push_back(samp);
+ samp = 1, 0, 0, 0; p.nonrelevant.push_back(samp);
+ samp = 0, 1, 0, 0; p.nonrelevant.push_back(samp);
+ samp = 0, 1, 0, 0; p.nonrelevant.push_back(samp);
+ samples.push_back(p);
+
+
+ trainer.set_c(10);
+
+ decision_function<kernel_type> df = trainer.train(samples);
+
+ dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples);
+ matrix<double,1,2> res;
+ res = 1,1;
+ DLIB_TEST(equal(test_ranking_function(df, samples), res));
+
+ DLIB_TEST(equal(test_ranking_function(trainer.train(samples[1]), samples), res));
+
+ trainer.set_epsilon(1e-13);
+ df = trainer.train(samples);
+
+ dlog << LINFO << df.basis_vectors(0);
+ sample_type truew;
+ truew = -0.5, -0.5, 0.5, 0.5;
+ DLIB_TEST(length(truew - df.basis_vectors(0)) < 1e-10);
+
+ dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples);
+ DLIB_TEST(equal(test_ranking_function(df, samples), res));
+
+ dlog << LINFO << "cv-accuracy: "<< cross_validate_ranking_trainer(trainer, samples,2);
+ DLIB_TEST(std::abs(cross_validate_ranking_trainer(trainer, samples,2)(0) - 0.7777777778) < 0.0001);
+
+ trainer.set_learns_nonnegative_weights(true);
+ df = trainer.train(samples);
+ truew = 0, 0, 1.0, 1.0;
+ dlog << LINFO << df.basis_vectors(0);
+ DLIB_TEST(length(truew - df.basis_vectors(0)) < 1e-10);
+ dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples);
+ DLIB_TEST(equal(test_ranking_function(df, samples), res));
+
+
+ samples.clear();
+ samples.push_back(p);
+ samples.push_back(p);
+ samples.push_back(p);
+ samples.push_back(p);
+ dlog << LINFO << "cv-accuracy: "<< cross_validate_ranking_trainer(trainer, samples,4);
+ DLIB_TEST(equal(cross_validate_ranking_trainer(trainer, samples,4) , res));
+
+ df.basis_vectors(0) = 0;
+ dlog << LINFO << "BAD RANKING:" << test_ranking_function(df, samples);
+ DLIB_TEST(test_ranking_function(df, samples)(1) < 0.5);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void dotest_sparse_vectors()
+ {
+ print_spinner();
+ dlog << LINFO << "in dotest_sparse_vectors()";
+
+ typedef std::map<unsigned long,double> sample_type;
+
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+
+ svm_rank_trainer<kernel_type> trainer;
+
+
+ std::vector<ranking_pair<sample_type> > samples;
+
+ ranking_pair<sample_type> p;
+ sample_type samp;
+
+ samp[3] = 1; p.relevant.push_back(samp); samp.clear();
+ samp[0] = 1; p.nonrelevant.push_back(samp); samp.clear();
+ samples.push_back(p);
+
+ samp[2] = 1; p.relevant.push_back(samp); samp.clear();
+ samp[0] = 1; p.nonrelevant.push_back(samp); samp.clear();
+ samp[1] = 1; p.nonrelevant.push_back(samp); samp.clear();
+ samp[1] = 1; p.nonrelevant.push_back(samp); samp.clear();
+ samples.push_back(p);
+
+
+ trainer.set_c(10);
+
+ decision_function<kernel_type> df = trainer.train(samples);
+
+ matrix<double,1,2> res;
+ res = 1,1;
+
+ dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples);
+ DLIB_TEST(equal(test_ranking_function(df, samples), res));
+
+ DLIB_TEST(equal(test_ranking_function(trainer.train(samples[1]), samples), res));
+
+ trainer.set_epsilon(1e-13);
+ df = trainer.train(samples);
+
+ dlog << LINFO << sparse_to_dense(df.basis_vectors(0));
+ sample_type truew;
+ truew[0] = -0.5;
+ truew[1] = -0.5;
+ truew[2] = 0.5;
+ truew[3] = 0.5;
+ DLIB_TEST(length(subtract(truew , df.basis_vectors(0))) < 1e-10);
+
+ dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples);
+ DLIB_TEST(equal(test_ranking_function(df, samples), res));
+
+ dlog << LINFO << "cv-accuracy: "<< cross_validate_ranking_trainer(trainer, samples,2);
+ DLIB_TEST(std::abs(cross_validate_ranking_trainer(trainer, samples,2)(0) - 0.7777777778) < 0.0001);
+
+ trainer.set_learns_nonnegative_weights(true);
+ df = trainer.train(samples);
+ truew[0] = 0.0;
+ truew[1] = 0.0;
+ truew[2] = 1.0;
+ truew[3] = 1.0;
+ dlog << LINFO << sparse_to_dense(df.basis_vectors(0));
+ DLIB_TEST(length(subtract(truew , df.basis_vectors(0))) < 1e-10);
+ dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples);
+ DLIB_TEST(equal(test_ranking_function(df, samples), res));
+
+
+ samples.clear();
+ samples.push_back(p);
+ samples.push_back(p);
+ samples.push_back(p);
+ samples.push_back(p);
+ dlog << LINFO << "cv-accuracy: "<< cross_validate_ranking_trainer(trainer, samples,4);
+ DLIB_TEST(equal(cross_validate_ranking_trainer(trainer, samples,4) , res) );
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename K, bool use_dcd_trainer>
+ class simple_rank_trainer
+ {
+ public:
+ template <typename T>
+ decision_function<K> train (
+ const ranking_pair<T>& pair
+ ) const
+ {
+ typedef matrix<double,10,1> sample_type;
+
+ std::vector<sample_type> relevant = pair.relevant;
+ std::vector<sample_type> nonrelevant = pair.nonrelevant;
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+ for (unsigned long i = 0; i < relevant.size(); ++i)
+ {
+ for (unsigned long j = 0; j < nonrelevant.size(); ++j)
+ {
+ samples.push_back(relevant[i] - nonrelevant[j]);
+ labels.push_back(+1);
+ samples.push_back(nonrelevant[i] - relevant[j]);
+ labels.push_back(-1);
+ }
+ }
+
+ if (use_dcd_trainer)
+ {
+ svm_c_linear_dcd_trainer<K> trainer;
+ trainer.set_c(1.0/samples.size());
+ trainer.set_epsilon(1e-10);
+ trainer.force_last_weight_to_1(true);
+ //trainer.be_verbose();
+ return trainer.train(samples, labels);
+ }
+ else
+ {
+ svm_c_linear_trainer<K> trainer;
+ trainer.set_c(1.0);
+ trainer.set_epsilon(1e-13);
+ trainer.force_last_weight_to_1(true);
+ //trainer.be_verbose();
+ decision_function<K> df = trainer.train(samples, labels);
+ DLIB_TEST_MSG(df.b == 0, df.b);
+ return df;
+ }
+ }
+ };
+
+ template <bool use_dcd_trainer>
+ void test_svmrank_weight_force_dense()
+ {
+ print_spinner();
+ dlog << LINFO << "use_dcd_trainer: "<< use_dcd_trainer;
+
+ typedef matrix<double,10,1> sample_type;
+ typedef linear_kernel<sample_type> kernel_type;
+
+ ranking_pair<sample_type> pair;
+
+ for (int i = 0; i < 20; ++i)
+ {
+ pair.relevant.push_back(abs(gaussian_randm(10,1,i)));
+ }
+
+ for (int i = 0; i < 20; ++i)
+ {
+ pair.nonrelevant.push_back(-abs(gaussian_randm(10,1,i+10000)));
+ pair.nonrelevant.back()(9) += 1;
+ }
+
+
+ svm_rank_trainer<kernel_type> trainer;
+ trainer.force_last_weight_to_1(true);
+ trainer.set_epsilon(1e-13);
+ //trainer.be_verbose();
+ decision_function<kernel_type> df;
+ df = trainer.train(pair);
+
+ matrix<double,1,2> res;
+ res = 1,1;
+ dlog << LINFO << "weights: "<< trans(df.basis_vectors(0));
+ const matrix<double,1,2> acc1 = test_ranking_function(df, pair);
+ dlog << LINFO << "ranking accuracy: " << acc1;
+ DLIB_TEST(equal(acc1,res));
+
+ simple_rank_trainer<kernel_type,use_dcd_trainer> strainer;
+ decision_function<kernel_type> df2;
+ df2 = strainer.train(pair);
+ dlog << LINFO << "weights: "<< trans(df2.basis_vectors(0));
+ const matrix<double,1,2> acc2 = test_ranking_function(df2, pair);
+ dlog << LINFO << "ranking accuracy: " << acc2;
+ DLIB_TEST(equal(acc2,res));
+
+ dlog << LINFO << "w error: " << max(abs(df.basis_vectors(0) - df2.basis_vectors(0)));
+ dlog << LINFO << "b error: " << abs(df.b - df2.b);
+ DLIB_TEST(std::abs(max(abs(df.basis_vectors(0) - df2.basis_vectors(0)))) < 1e-8);
+ DLIB_TEST(std::abs(abs(df.b - df2.b)) < 1e-8);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_dnn_ranking_loss()
+ {
+ print_spinner();
+ typedef matrix<double,2,1> sample_type;
+
+
+ ranking_pair<sample_type> data;
+ sample_type samp;
+
+ // Make one relevant example.
+ samp = 1, 0;
+ data.relevant.push_back(samp);
+
+ // Now make a non-relevant example.
+ samp = 0, 1;
+ data.nonrelevant.push_back(samp);
+
+
+ using net_type = loss_ranking<fc_no_bias<1,input<matrix<float,2,1>>>>;
+ net_type net;
+ dnn_trainer<net_type> trainer(net, sgd(1.0, 0.9));
+ std::vector<matrix<float,2,1>> x;
+ std::vector<float> y;
+
+ x.push_back(matrix_cast<float>(data.relevant[0])); y.push_back(1);
+ x.push_back(matrix_cast<float>(data.nonrelevant[0])); y.push_back(-1);
+
+ //trainer.be_verbose();
+ trainer.set_learning_rate_schedule(logspace(-1, -7, 4000));
+ trainer.train(x,y);
+
+ matrix<float> params = mat(net.subnet().layer_details().get_layer_params());
+ dlog << LINFO << "params: "<< params;
+ dlog << LINFO << "relevant output score: " << net(x[0]);
+ dlog << LINFO << "nonrelevant output score: " << net(x[1]);
+
+ DLIB_TEST(std::abs(params(0) - 1) < 0.001);
+ DLIB_TEST(std::abs(params(1) + 1) < 0.001);
+ DLIB_TEST(std::abs(net(x[0]) - 1) < 0.001);
+ DLIB_TEST(std::abs(net(x[1]) + 1) < 0.001);
+ }
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+ class test_ranking_tools : public tester
+ {
+ public:
+ test_ranking_tools (
+ ) :
+ tester ("test_ranking",
+ "Runs tests on the ranking tools.")
+ {}
+
+
+ void perform_test (
+ )
+ {
+ test_count_ranking_inversions();
+ dotest1();
+ dotest_sparse_vectors();
+ test_svmrank_weight_force_dense<true>();
+ test_svmrank_weight_force_dense<false>();
+ run_prior_test();
+ run_prior_sparse_test();
+ test_dnn_ranking_loss();
+
+ }
+ } a;
+
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/read_write_mutex.cpp b/ml/dlib/dlib/test/read_write_mutex.cpp
new file mode 100644
index 000000000..fb8bdb84c
--- /dev/null
+++ b/ml/dlib/dlib/test/read_write_mutex.cpp
@@ -0,0 +1,208 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/misc_api.h>
+#include <dlib/threads.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.read_write_mutex");
+
+ class read_write_mutex_tester : public tester, multithreaded_object
+ {
+ public:
+ read_write_mutex_tester (
+ ) :
+ tester ("test_read_write_mutex",
+ "Runs tests on the read_write_mutex component.")
+ {
+ register_thread(*this, &read_write_mutex_tester::thread_write);
+ register_thread(*this, &read_write_mutex_tester::thread_write);
+ register_thread(*this, &read_write_mutex_tester::thread_write);
+
+ register_thread(*this, &read_write_mutex_tester::thread_readonly);
+ register_thread(*this, &read_write_mutex_tester::thread_readonly);
+ register_thread(*this, &read_write_mutex_tester::thread_readonly);
+ register_thread(*this, &read_write_mutex_tester::thread_readonly2);
+ register_thread(*this, &read_write_mutex_tester::thread_readonly2);
+ register_thread(*this, &read_write_mutex_tester::thread_readonly2);
+
+ }
+
+ read_write_mutex m;
+
+ dlib::mutex mut;
+ int num_write;
+ int num_read;
+ int max_read;
+
+ bool failure;
+
+ void thread_write ()
+ {
+ // do this so that the readonly threads can get into their loops first. This way
+ // we can see if the mutex lets many readers into their area
+ dlib::sleep(250);
+ for (int i = 0; i < 6; ++i)
+ {
+ auto_mutex lock(m);
+
+ mut.lock();
+ ++num_write;
+ mut.unlock();
+
+ // only one write thread should ever be active at once
+ if (num_write != 1)
+ {
+ failure = true;
+ dlog << LERROR << "1";
+ }
+
+ dlib::sleep(300);
+
+ // only one write thread should ever be active at once
+ if (num_write != 1)
+ {
+ failure = true;
+ dlog << LERROR << "2";
+ }
+
+ mut.lock();
+ --num_write;
+ mut.unlock();
+
+ print_spinner();
+ }
+ dlog << LINFO << "exit thread_write()";
+ }
+
+ void do_readonly_stuff()
+ {
+ mut.lock();
+ ++num_read;
+ max_read = max(num_read, max_read);
+ mut.unlock();
+
+ if (num_write != 0)
+ {
+ failure = true;
+ dlog << LERROR << "3";
+ }
+
+ dlib::sleep(300);
+
+ if (num_write != 0)
+ {
+ failure = true;
+ dlog << LERROR << "4";
+ }
+
+ mut.lock();
+ max_read = max(num_read, max_read);
+ --num_read;
+ mut.unlock();
+
+ print_spinner();
+ }
+
+ void thread_readonly ()
+ {
+ for (int i = 0; i < 6; ++i)
+ {
+ auto_mutex_readonly lock(m);
+ DLIB_TEST(lock.has_read_lock());
+ DLIB_TEST(!lock.has_write_lock());
+ do_readonly_stuff();
+
+ lock.lock_readonly();
+ DLIB_TEST(lock.has_read_lock());
+ DLIB_TEST(!lock.has_write_lock());
+ lock.unlock();
+ DLIB_TEST(!lock.has_read_lock());
+ DLIB_TEST(!lock.has_write_lock());
+ lock.lock_readonly();
+ DLIB_TEST(lock.has_read_lock());
+ DLIB_TEST(!lock.has_write_lock());
+ lock.lock_write();
+ DLIB_TEST(!lock.has_read_lock());
+ DLIB_TEST(lock.has_write_lock());
+ lock.lock_write();
+ DLIB_TEST(!lock.has_read_lock());
+ DLIB_TEST(lock.has_write_lock());
+ }
+
+ dlog << LINFO << "exit thread_readonly()";
+ }
+
+ void thread_readonly2 ()
+ {
+ for (int i = 0; i < 6; ++i)
+ {
+ m.lock_readonly();
+ auto_unlock_readonly unlock(m);
+
+ do_readonly_stuff();
+ }
+ dlog << LINFO << "exit thread_readonly2()";
+ }
+
+
+ void perform_test (
+ )
+ {
+ num_write = 0;
+ num_read = 0;
+ max_read = 0;
+ failure = false;
+
+ // doing this big block of weird stuff should have no effect.
+ {
+ m.unlock();
+
+ m.lock_readonly();
+ m.lock_readonly();
+ m.unlock();
+ m.unlock_readonly();
+ m.unlock();
+ m.unlock_readonly();
+
+ m.unlock();
+ m.unlock_readonly();
+
+ m.lock();
+ m.unlock_readonly();
+ m.unlock_readonly();
+ m.unlock();
+ }
+
+
+ // start up our testing threads
+ start();
+
+ // wait for the threads to finish
+ wait();
+
+
+ DLIB_TEST(failure == false);
+ DLIB_TEST_MSG(max_read == 6, "max_read: "<< max_read);
+
+ }
+
+ } a;
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/reference_counter.cpp b/ml/dlib/dlib/test/reference_counter.cpp
new file mode 100644
index 000000000..330ceed94
--- /dev/null
+++ b/ml/dlib/dlib/test/reference_counter.cpp
@@ -0,0 +1,122 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/reference_counter.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.reference_counter");
+
+ template <
+ typename ref_counter
+ >
+ void reference_counter_test (
+ )
+ /*!
+ requires
+ - ref_counter is an implementation of reference_counter/reference_counter_kernel_abstract.h
+ and is instantiated to contain an int
+ ensures
+ - runs tests on reference_counter for compliance with the specs
+ !*/
+ {
+
+ ref_counter a, b, c;
+
+ for (long i = 0; i < 10; ++i)
+ {
+ print_spinner();
+ for (long j = 0; j < 10000; ++j)
+ {
+ a.modify() = j;
+ b.modify() = j+1;
+ c.modify() = j+2;
+ DLIB_ASSERT(a.access() == j,"");
+ DLIB_ASSERT(b.access() == j+1,"");
+ DLIB_ASSERT(c.access() == j+2,"");
+ DLIB_ASSERT(a.modify() == j,"");
+ DLIB_ASSERT(b.modify() == j+1,"");
+ DLIB_ASSERT(c.modify() == j+2,"");
+ DLIB_ASSERT(a.access() == j,"");
+ DLIB_ASSERT(b.access() == j+1,"");
+ DLIB_ASSERT(c.access() == j+2,"");
+ DLIB_ASSERT(a.modify() == j,"");
+ DLIB_ASSERT(b.modify() == j+1,"");
+ DLIB_ASSERT(c.modify() == j+2,"");
+ a = c;
+ DLIB_ASSERT(a.access() == j+2,"");
+ DLIB_ASSERT(b.access() == j+1,"");
+ DLIB_ASSERT(c.access() == j+2,"");
+ DLIB_ASSERT(a.modify() == j+2,"");
+ DLIB_ASSERT(b.modify() == j+1,"");
+ DLIB_ASSERT(c.modify() == j+2,"");
+ DLIB_ASSERT(a.access() == j+2,"");
+ DLIB_ASSERT(b.access() == j+1,"");
+ DLIB_ASSERT(c.access() == j+2,"");
+ DLIB_ASSERT(a.modify() == j+2,"");
+ DLIB_ASSERT(b.modify() == j+1,"");
+ DLIB_ASSERT(c.modify() == j+2,"");
+
+ a = b = c;
+ DLIB_ASSERT(a.access() == b.access(),"");
+ DLIB_ASSERT(a.access() == c.access(),"");
+ DLIB_ASSERT(c.access() == b.access(),"");
+ a.modify() = j;
+ DLIB_ASSERT(a.access() == j,"");
+ DLIB_ASSERT(a.access() != b.access(),"");
+ DLIB_ASSERT(a.access() != c.access(),"");
+ DLIB_ASSERT(c.access() == b.access(),"");
+ DLIB_ASSERT(c.access() == j+2,"");
+ DLIB_ASSERT(b.access() == j+2,"");
+
+ DLIB_ASSERT(a.access() == j,"");
+ a = a;
+ DLIB_ASSERT(a.access() == j,"");
+ c = c;
+ DLIB_ASSERT(c.access() == j+2,"");
+ DLIB_ASSERT(b.access() == j+2,"");
+ swap(a,c);
+ DLIB_ASSERT(a.access() == j+2,"");
+ DLIB_ASSERT(c.access() == j,"");
+ DLIB_ASSERT(b.access() == j+2,"");
+ }
+ }
+
+ }
+
+
+
+
+
+ class reference_counter_tester : public tester
+ {
+ public:
+ reference_counter_tester (
+ ) :
+ tester ("test_reference_counter",
+ "Runs tests on the reference_counter component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ reference_counter_test<reference_counter<int>::kernel_1a> ();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/rls.cpp b/ml/dlib/dlib/test/rls.cpp
new file mode 100644
index 000000000..c4516ad74
--- /dev/null
+++ b/ml/dlib/dlib/test/rls.cpp
@@ -0,0 +1,196 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <cmath>
+#include <dlib/svm.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.rls");
+
+
+ void test_rls()
+ {
+ dlib::rand rnd;
+
+ running_stats<double> rs1, rs2, rs3, rs4, rs5;
+
+ for (int k = 0; k < 2; ++k)
+ {
+ for (long num_vars = 1; num_vars < 4; ++num_vars)
+ {
+ print_spinner();
+ for (long size = 1; size < 300; ++size)
+ {
+ {
+ matrix<double> X = randm(size,num_vars,rnd);
+ matrix<double,0,1> Y = randm(size,1,rnd);
+
+
+ const double C = 1000;
+ const double forget_factor = 1.0;
+ rls r(forget_factor, C);
+ for (long i = 0; i < Y.size(); ++i)
+ {
+ r.train(trans(rowm(X,i)), Y(i));
+ }
+
+
+ matrix<double> w = pinv(1.0/C*identity_matrix<double>(X.nc()) + trans(X)*X)*trans(X)*Y;
+
+ rs1.add(length(r.get_w() - w));
+ }
+
+ {
+ matrix<double> X = randm(size,num_vars,rnd);
+ matrix<double,0,1> Y = randm(size,1,rnd);
+
+ matrix<double,0,1> G(size,1);
+
+ const double C = 10000;
+ const double forget_factor = 0.8;
+ rls r(forget_factor, C);
+ for (long i = 0; i < Y.size(); ++i)
+ {
+ r.train(trans(rowm(X,i)), Y(i));
+
+ G(i) = std::pow(forget_factor, i/2.0);
+ }
+
+ G = flipud(G);
+
+ X = diagm(G)*X;
+ Y = diagm(G)*Y;
+
+ matrix<double> w = pinv(1.0/C*identity_matrix<double>(X.nc()) + trans(X)*X)*trans(X)*Y;
+
+ rs5.add(length(r.get_w() - w));
+ }
+
+ {
+ matrix<double> X = randm(size,num_vars,rnd);
+ matrix<double> Y = colm(X,0)*10;
+
+
+ const double C = 1000000;
+ const double forget_factor = 1.0;
+ rls r(forget_factor, C);
+ for (long i = 0; i < Y.size(); ++i)
+ {
+ r.train(trans(rowm(X,i)), Y(i));
+ }
+
+
+ matrix<double> w = pinv(1.0/C*identity_matrix<double>(X.nc()) + trans(X)*X)*trans(X)*Y;
+
+ rs2.add(length(r.get_w() - w));
+ }
+
+ {
+ matrix<double> X = join_rows(randm(size,num_vars,rnd)-0.5, ones_matrix<double>(size,1));
+ matrix<double> Y = uniform_matrix<double>(size,1,10);
+
+
+ const double C = 1e7;
+ const double forget_factor = 1.0;
+
+ matrix<double> w = pinv(1.0/C*identity_matrix<double>(X.nc()) + trans(X)*X)*trans(X)*Y;
+
+ rls r(forget_factor, C);
+ for (long i = 0; i < Y.size(); ++i)
+ {
+ r.train(trans(rowm(X,i)), Y(i));
+ rs3.add(std::abs(r(trans(rowm(X,i))) - 10));
+ }
+
+
+ }
+ {
+ matrix<double> X = randm(size,num_vars,rnd)-0.5;
+ matrix<double> Y = colm(X,0)*10;
+
+
+ const double C = 1e6;
+ const double forget_factor = 0.7;
+
+
+ rls r(forget_factor, C);
+ DLIB_TEST(std::abs(r.get_c() - C) < 1e-10);
+ DLIB_TEST(std::abs(r.get_forget_factor() - forget_factor) < 1e-15);
+ DLIB_TEST(r.get_w().size() == 0);
+
+ for (long i = 0; i < Y.size(); ++i)
+ {
+ r.train(trans(rowm(X,i)), Y(i));
+ rs4.add(std::abs(r(trans(rowm(X,i))) - X(i,0)*10));
+ }
+
+ DLIB_TEST(r.get_w().size() == num_vars);
+
+ decision_function<linear_kernel<matrix<double,0,1> > > df = r.get_decision_function();
+ DLIB_TEST(std::abs(df(trans(rowm(X,0))) - r(trans(rowm(X,0)))) < 1e-15);
+ }
+ }
+ }
+ }
+
+ dlog << LINFO << "rs1.mean(): " << rs1.mean();
+ dlog << LINFO << "rs2.mean(): " << rs2.mean();
+ dlog << LINFO << "rs3.mean(): " << rs3.mean();
+ dlog << LINFO << "rs4.mean(): " << rs4.mean();
+ dlog << LINFO << "rs5.mean(): " << rs5.mean();
+ dlog << LINFO << "rs1.max(): " << rs1.max();
+ dlog << LINFO << "rs2.max(): " << rs2.max();
+ dlog << LINFO << "rs3.max(): " << rs3.max();
+ dlog << LINFO << "rs4.max(): " << rs4.max();
+ dlog << LINFO << "rs5.max(): " << rs5.max();
+
+ DLIB_TEST_MSG(rs1.mean() < 1e-10, rs1.mean());
+ DLIB_TEST_MSG(rs2.mean() < 1e-9, rs2.mean());
+ DLIB_TEST_MSG(rs3.mean() < 1e-6, rs3.mean());
+ DLIB_TEST_MSG(rs4.mean() < 1e-6, rs4.mean());
+ DLIB_TEST_MSG(rs5.mean() < 1e-3, rs5.mean());
+
+ DLIB_TEST_MSG(rs1.max() < 1e-10, rs1.max());
+ DLIB_TEST_MSG(rs2.max() < 1e-6, rs2.max());
+ DLIB_TEST_MSG(rs3.max() < 0.001, rs3.max());
+ DLIB_TEST_MSG(rs4.max() < 0.01, rs4.max());
+ DLIB_TEST_MSG(rs5.max() < 0.1, rs5.max());
+
+ }
+
+
+
+
+ class rls_tester : public tester
+ {
+ public:
+ rls_tester (
+ ) :
+ tester ("test_rls",
+ "Runs tests on the rls component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_rls();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/sammon.cpp b/ml/dlib/dlib/test/sammon.cpp
new file mode 100644
index 000000000..5328bd1f6
--- /dev/null
+++ b/ml/dlib/dlib/test/sammon.cpp
@@ -0,0 +1,211 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <cmath>
+#include <dlib/statistics.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.sammon");
+
+
+ std::vector<matrix<double,4,1> > make_test_data4(
+ )
+ {
+ std::vector<matrix<double,4,1> > data;
+
+ matrix<double,4,1> m;
+
+ m = 0,0,0, 0; data.push_back(m);
+ m = 1,0,0, 0; data.push_back(m);
+ m = 0,1,0, 0; data.push_back(m);
+ m = 0,0,1, 0; data.push_back(m);
+
+ return data;
+ }
+
+ std::vector<matrix<double,3,1> > make_test_data3(
+ )
+ {
+ std::vector<matrix<double,3,1> > data;
+
+ matrix<double,3,1> m;
+
+ m = 0,0,0; data.push_back(m);
+ m = 1,0,0; data.push_back(m);
+ m = 0,1,0; data.push_back(m);
+ m = 0,0,1; data.push_back(m);
+
+ return data;
+ }
+
+ std::vector<matrix<double> > make_test_data3d(
+ )
+ {
+ std::vector<matrix<double> > data;
+
+ matrix<double,3,1> m;
+
+ m = 0,0,0; data.push_back(m);
+ m = 1,0,0; data.push_back(m);
+ m = 0,1,0; data.push_back(m);
+ m = 0,0,1; data.push_back(m);
+
+ return data;
+ }
+
+
+ void runtest()
+ {
+ sammon_projection s;
+ std::vector<matrix<double, 0, 1> > projs = s(make_test_data3(),2);
+ running_stats<double> rs1, rs2;
+
+ rs1.add(length(projs[0] - projs[1]));
+ rs1.add(length(projs[0] - projs[2]));
+ rs1.add(length(projs[0] - projs[3]));
+
+ rs2.add(length(projs[1] - projs[2]));
+ rs2.add(length(projs[2] - projs[3]));
+ rs2.add(length(projs[3] - projs[1]));
+
+ DLIB_TEST(rs1.stddev()/rs1.mean() < 1e-4);
+ DLIB_TEST(rs2.stddev()/rs2.mean() < 1e-4);
+
+
+
+ projs = s(make_test_data4(),2);
+ rs1.clear();
+ rs2.clear();
+
+ rs1.add(length(projs[0] - projs[1]));
+ rs1.add(length(projs[0] - projs[2]));
+ rs1.add(length(projs[0] - projs[3]));
+
+ rs2.add(length(projs[1] - projs[2]));
+ rs2.add(length(projs[2] - projs[3]));
+ rs2.add(length(projs[3] - projs[1]));
+
+ DLIB_TEST(rs1.stddev()/rs1.mean() < 1e-4);
+ DLIB_TEST(rs2.stddev()/rs2.mean() < 1e-4);
+
+ projs = s(make_test_data3d(),2);
+ rs1.clear();
+ rs2.clear();
+
+ rs1.add(length(projs[0] - projs[1]));
+ rs1.add(length(projs[0] - projs[2]));
+ rs1.add(length(projs[0] - projs[3]));
+
+ rs2.add(length(projs[1] - projs[2]));
+ rs2.add(length(projs[2] - projs[3]));
+ rs2.add(length(projs[3] - projs[1]));
+
+ DLIB_TEST(rs1.stddev()/rs1.mean() < 1e-4);
+ DLIB_TEST(rs2.stddev()/rs2.mean() < 1e-4);
+ }
+
+ void runtest2()
+ {
+ sammon_projection s;
+ std::vector<matrix<double, 0, 1> > projs, temp;
+
+ DLIB_TEST(s(projs,3).size() == 0);
+
+ matrix<double,2,1> m;
+ m = 1,2;
+ projs.push_back(m);
+ temp = s(projs,2);
+ DLIB_TEST(temp.size() == 1);
+ DLIB_TEST(temp[0].size() == 2);
+
+ projs.push_back(m);
+ temp = s(projs,1);
+ DLIB_TEST(temp.size() == 2);
+ DLIB_TEST(temp[0].size() == 1);
+ DLIB_TEST(temp[1].size() == 1);
+ }
+
+ void runtest3(int num_dims)
+ {
+ sammon_projection s;
+ std::vector<matrix<double, 0, 1> > projs;
+ matrix<double,3,1> m;
+ m = 1, 1, 1;
+ projs.push_back(m);
+
+ m = 1, 2, 1;
+ projs.push_back(m);
+
+ m = 1, 3, 1;
+ projs.push_back(m);
+
+ projs = s(projs,num_dims);
+
+ const double d1a = length(projs[0] - projs[1]);
+ const double d1b = length(projs[1] - projs[2]);
+ const double d2 = length(projs[0] - projs[2]);
+
+ DLIB_TEST(std::abs(d1a-d1b)/d1a < 1e-8);
+ DLIB_TEST(std::abs(d2/d1a-2) < 1e-8);
+ }
+
+ void runtest4(int num_dims)
+ {
+ sammon_projection s;
+ std::vector<matrix<double, 0, 1> > projs;
+ matrix<double,3,1> m;
+ m = 1, 1, 1;
+ projs.push_back(m);
+
+ m = 1, 2, 1;
+ projs.push_back(m);
+
+
+ projs = s(projs,num_dims);
+
+ DLIB_TEST(length(projs[0] - projs[1]) > 1e-5);
+ }
+
+ class sammon_tester : public tester
+ {
+ public:
+ sammon_tester (
+ ) :
+ tester ("test_sammon",
+ "Runs tests on the sammon_projection component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ runtest();
+ print_spinner();
+ runtest2();
+ print_spinner();
+ runtest3(2);
+ print_spinner();
+ runtest4(2);
+ runtest3(1);
+ print_spinner();
+ runtest4(1);
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/scan_image.cpp b/ml/dlib/dlib/test/scan_image.cpp
new file mode 100644
index 000000000..c3a0115e3
--- /dev/null
+++ b/ml/dlib/dlib/test/scan_image.cpp
@@ -0,0 +1,713 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include "dlib/image_processing.h"
+
+#include "dlib/test/tester.h"
+
+#include "dlib/image_transforms.h"
+#include "dlib/pixel.h"
+#include "dlib/array2d.h"
+#include "dlib/array.h"
+
+// ----------------------------------------------------------------------------------------
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ using dlib::array;
+
+ // Declare the logger we will use in this test. The name of the tester
+ // should start with "test."
+ logger dlog("test.scan_image");
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename image_type1, typename image_type2>
+ void sum_filter_i (
+ const image_type1& img,
+ image_type2& out,
+ const rectangle& rect
+ )
+ {
+ typedef typename image_type1::type pixel_type;
+ typedef typename promote<pixel_type>::type ptype;
+ integral_image_generic<ptype> iimg;
+ iimg.load(img);
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ const rectangle temp = translate_rect(rect, point(c,r)).intersect(get_rect(iimg));
+ if (temp.is_empty() == false)
+ out[r][c] += iimg.get_sum_of_area(temp);
+ }
+ }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_array_type
+ >
+ void scan_image_i (
+ std::vector<std::pair<double, point> >& dets,
+ const image_array_type& images,
+ const std::vector<std::pair<unsigned int, rectangle> >& rects,
+ const double thresh,
+ const unsigned long max_dets
+ )
+ {
+ typedef typename image_array_type::type::type pixel_type;
+ typedef typename promote<pixel_type>::type ptype;
+ array<integral_image_generic<ptype> > iimg;
+ iimg.set_max_size(images.size());
+ iimg.set_size(images.size());
+
+ for (unsigned long i = 0; i < iimg.size(); ++i)
+ iimg[i].load(images[i]);
+
+
+ dets.clear();
+
+
+ for (long r = 0; r < images[0].nr(); ++r)
+ {
+ for (long c = 0; c < images[0].nc(); ++c)
+ {
+ ptype temp = 0;
+ for (unsigned long i = 0; i < rects.size(); ++i)
+ {
+ rectangle rtemp = translate_rect(rects[i].second,point(c,r)).intersect(get_rect(images[0]));
+ if (rtemp.is_empty() == false)
+ temp += iimg[rects[i].first].get_sum_of_area(rtemp);
+ }
+ if (temp > thresh)
+ {
+ dets.push_back(std::make_pair(temp, point(c,r)));
+
+ if (dets.size() >= max_dets)
+ return;
+
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_array_type
+ >
+ void scan_image_old (
+ std::vector<std::pair<double, point> >& dets,
+ const image_array_type& images,
+ const std::vector<std::pair<unsigned int, rectangle> >& rects,
+ const double thresh,
+ const unsigned long max_dets
+ )
+ {
+ dets.clear();
+ if (max_dets == 0)
+ return;
+
+ typedef typename image_array_type::type::type pixel_type;
+ typedef typename promote<pixel_type>::type ptype;
+
+ std::vector<std::vector<ptype> > column_sums(rects.size());
+ for (unsigned long i = 0; i < column_sums.size(); ++i)
+ {
+ const typename image_array_type::type& img = images[rects[i].first];
+ column_sums[i].resize(img.nc() + rects[i].second.width(),0);
+
+ const long top = -1 + rects[i].second.top();
+ const long bottom = -1 + rects[i].second.bottom();
+ long left = rects[i].second.left()-1;
+
+ // initialize column_sums[i] at row -1
+ for (unsigned long j = 0; j < column_sums[i].size(); ++j)
+ {
+ rectangle strip(left,top,left,bottom);
+ strip = strip.intersect(get_rect(img));
+ if (!strip.is_empty())
+ {
+ column_sums[i][j] = sum(matrix_cast<ptype>(subm(mat(img),strip)));
+ }
+
+ ++left;
+ }
+ }
+
+
+ const rectangle area = get_rect(images[0]);
+
+ for (long r = 0; r < images[0].nr(); ++r)
+ {
+ // set to sum at point(-1,r). i.e. should be equal to sum_of_rects_in_images(images, rects, point(-1,r))
+ // We compute it's value in the next loop.
+ ptype cur_sum = 0;
+
+ // Update the first part of column_sums since we only work on the c+width part of column_sums
+ // in the main loop.
+ for (unsigned long i = 0; i < rects.size(); ++i)
+ {
+ const typename image_array_type::type& img = images[rects[i].first];
+ const long top = r + rects[i].second.top() - 1;
+ const long bottom = r + rects[i].second.bottom();
+ const long width = rects[i].second.width();
+ for (long k = 0; k < width; ++k)
+ {
+ const long right = k-width + rects[i].second.right();
+
+ const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;
+ const ptype tr_corner = area.contains(right,top) ? img[top][right] : 0;
+ // update the sum in this column now that we are on the next row
+ column_sums[i][k] = column_sums[i][k] + br_corner - tr_corner;
+ cur_sum += column_sums[i][k];
+ }
+ }
+
+ for (long c = 0; c < images[0].nc(); ++c)
+ {
+ for (unsigned long i = 0; i < rects.size(); ++i)
+ {
+ const typename image_array_type::type& img = images[rects[i].first];
+ const long top = r + rects[i].second.top() - 1;
+ const long bottom = r + rects[i].second.bottom();
+ const long right = c + rects[i].second.right();
+ const long width = rects[i].second.width();
+
+ const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;
+ const ptype tr_corner = area.contains(right,top) ? img[top][right] : 0;
+ // update the sum in this column now that we are on the next row
+ column_sums[i][c+width] = column_sums[i][c+width] + br_corner - tr_corner;
+
+
+ // add in the new right side of the rect and subtract the old right side.
+ cur_sum = cur_sum + column_sums[i][c+width] - column_sums[i][c];
+
+ }
+
+ if (cur_sum > thresh)
+ {
+ dets.push_back(std::make_pair(cur_sum, point(c,r)));
+
+ if (dets.size() >= max_dets)
+ return;
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_test1()
+ {
+ dlog << LINFO << "run_test1()";
+
+ print_spinner();
+ array2d<unsigned char> img, temp_img;
+ img.set_size(600,600);
+ assign_all_pixels(img,0);
+ rectangle rect = centered_rect(10,10,5,5);
+ dlog << LTRACE << "expected: 10,10";
+ fill_rect(img, rect, 255);
+
+
+ array<array2d<unsigned char> > images;
+ std::vector<std::pair<unsigned int, rectangle> > rects;
+ for (int i = 0; i < 10; ++i)
+ {
+ assign_image(temp_img, img);
+ images.push_back(temp_img);
+ rects.push_back(make_pair(i,centered_rect(0,0,5,5)));
+ }
+
+ std::vector<std::pair<double, point> > dets, dets2, dets3;
+
+
+ dlog << LTRACE << "best score: "<< sum_of_rects_in_images(images,rects,point(10,10));
+ scan_image(dets,images,rects,30000, 100);
+ scan_image_i(dets2,images,rects,30000, 100);
+ scan_image_old(dets3,images,rects,30000, 100);
+
+
+
+ dlog << LTRACE << "dets.size(): "<< dets.size();
+ dlog << LTRACE << "dets2.size(): "<< dets2.size();
+ dlog << LTRACE << "dets3.size(): "<< dets3.size();
+
+ DLIB_TEST(dets.size() == dets2.size());
+ DLIB_TEST(dets.size() == dets3.size());
+
+ for (unsigned long i = 0; i < dets.size(); ++i)
+ {
+ //dlog << LTRACE << "dets["<<i<<"]: " << dets[i].second << " -> " << dets[i].first;
+ //dlog << LTRACE << "dets2["<<i<<"]: " << dets2[i].second << " -> " << dets2[i].first;
+ //dlog << LTRACE << "dets3["<<i<<"]: " << dets3[i].second << " -> " << dets3[i].first;
+
+ DLIB_TEST(sum_of_rects_in_images(images, rects, dets[i].second) == dets[i].first);
+ DLIB_TEST(sum_of_rects_in_images(images, rects, dets2[i].second) == dets2[i].first);
+ DLIB_TEST(sum_of_rects_in_images(images, rects, dets3[i].second) == dets3[i].first);
+ }
+
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void run_test2()
+ {
+ print_spinner();
+ dlog << LINFO << "run_test2()";
+ array2d<unsigned char> img, temp_img;
+ img.set_size(600,600);
+ assign_all_pixels(img,0);
+ rectangle rect = centered_rect(10,11,5,6);
+ dlog << LTRACE << "expected: 10,11";
+ fill_rect(img, rect, 255);
+
+
+ array<array2d<unsigned char> > images;
+ std::vector<std::pair<unsigned int, rectangle> > rects;
+ for (int i = 0; i < 10; ++i)
+ {
+ assign_image(temp_img, img);
+ images.push_back(temp_img);
+ rects.push_back(make_pair(i,centered_rect(0,0,5,5)));
+ rects.push_back(make_pair(i,centered_rect(3,2,5,6)));
+ }
+
+ std::vector<std::pair<double, point> > dets, dets2, dets3;
+
+
+ scan_image(dets,images,rects,30000, 100);
+ scan_image_i(dets2,images,rects,30000, 100);
+ scan_image_old(dets3,images,rects,30000, 100);
+
+
+
+ dlog << LTRACE << "dets.size(): "<< dets.size();
+ dlog << LTRACE << "dets2.size(): "<< dets2.size();
+ dlog << LTRACE << "dets3.size(): "<< dets3.size();
+
+ DLIB_TEST(dets.size() == dets2.size());
+ DLIB_TEST(dets.size() == dets3.size());
+
+ for (unsigned long i = 0; i < dets.size(); ++i)
+ {
+ //dlog << LTRACE << "dets["<<i<<"]: " << dets[i].second << " -> " << dets[i].first;
+ //dlog << LTRACE << "dets2["<<i<<"]: " << dets2[i].second << " -> " << dets2[i].first;
+ //dlog << LTRACE << "dets3["<<i<<"]: " << dets3[i].second << " -> " << dets3[i].first;
+
+ DLIB_TEST(sum_of_rects_in_images(images, rects, dets[i].second) == dets[i].first);
+ DLIB_TEST(sum_of_rects_in_images(images, rects, dets2[i].second) == dets2[i].first);
+ DLIB_TEST(sum_of_rects_in_images(images, rects, dets3[i].second) == dets3[i].first);
+ }
+
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename pixel_type>
+ void run_test3(const double thresh)
+ {
+ dlog << LINFO << "running run_test3("<<thresh<<")";
+ dlib::rand rnd;
+
+ rnd.set_seed("235");
+
+ array<array2d<pixel_type> > images;
+ images.resize(1);
+ images[0].set_size(200,180);
+
+ for (int iter = 0; iter < 50; ++iter)
+ {
+ print_spinner();
+ assign_all_pixels(images[0], thresh - 0.0001);
+
+ for (int i = 0; i < 20; ++i)
+ {
+ point p1(rnd.get_random_32bit_number()%images[0].nc(),
+ rnd.get_random_32bit_number()%images[0].nr());
+ point p2(rnd.get_random_32bit_number()%images[0].nc(),
+ rnd.get_random_32bit_number()%images[0].nr());
+
+ rectangle rect(p1,p2);
+ fill_rect(images[0], rect, static_cast<pixel_type>(rnd.get_random_double()*10 - 5));
+ }
+
+ std::vector<std::pair<unsigned int, rectangle> > rects;
+ rects.push_back(make_pair(0,centered_rect(0,0,1+rnd.get_random_32bit_number()%40,1+rnd.get_random_32bit_number()%40)));
+ rects.push_back(make_pair(0,centered_rect(0,0,1+rnd.get_random_32bit_number()%40,1+rnd.get_random_32bit_number()%40)));
+
+
+
+
+ std::vector<std::pair<double, point> > dets, dets2, dets3;
+ scan_image(dets,images,rects,thresh, 100);
+ scan_image_i(dets2,images,rects,thresh, 100);
+ scan_image_old(dets3,images,rects,thresh, 100);
+
+ dlog << LTRACE << "dets.size(): "<< dets.size();
+ dlog << LTRACE << "dets2.size(): "<< dets2.size();
+ dlog << LTRACE << "dets3.size(): "<< dets3.size();
+
+ DLIB_TEST(dets.size() == dets2.size());
+ DLIB_TEST(dets.size() == dets3.size());
+
+ for (unsigned long i = 0; i < dets.size(); ++i)
+ {
+ //dlog << LTRACE << "dets["<<i<<"]: " << dets[i].second << " -> " << dets[i].first;
+ //dlog << LTRACE << "dets2["<<i<<"]: " << dets2[i].second << " -> " << dets2[i].first;
+ //dlog << LTRACE << "dets3["<<i<<"]: " << dets3[i].second << " -> " << dets3[i].first;
+
+ DLIB_TEST_MSG(std::abs(sum_of_rects_in_images(images, rects, dets[i].second) - dets[i].first) < 1e-6,
+ "error: "<< sum_of_rects_in_images(images, rects, dets[i].second) - dets[i].first
+ << " dets["<<i<<"].second: " << dets[i].second
+ );
+ DLIB_TEST_MSG(std::abs(sum_of_rects_in_images(images, rects, dets2[i].second) - dets2[i].first) < 1e-6,
+ sum_of_rects_in_images(images, rects, dets2[i].second) - dets2[i].first
+ );
+ DLIB_TEST_MSG(std::abs(sum_of_rects_in_images(images, rects, dets3[i].second) - dets3[i].first) < 1e-6,
+ "error: "<< sum_of_rects_in_images(images, rects, dets3[i].second) - dets3[i].first
+ << " dets3["<<i<<"].first: " << dets3[i].first
+ << " dets3["<<i<<"].second: " << dets3[i].second
+ );
+ }
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename pixel_type>
+ void test_sum_filter (
+ )
+ {
+ dlib::rand rnd;
+
+ for (int k = 0; k < 20; ++k)
+ {
+ print_spinner();
+
+ array2d<pixel_type> img(1 + rnd.get_random_32bit_number()%100,
+ 1 + rnd.get_random_32bit_number()%100);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ img[r][c] = static_cast<pixel_type>(100*(rnd.get_random_double()-0.5));
+ }
+ }
+
+ array2d<long> test1(img.nr(), img.nc());
+ array2d<double> test2(img.nr(), img.nc());
+ array2d<long> test1_i(img.nr(), img.nc());
+ array2d<double> test2_i(img.nr(), img.nc());
+
+ assign_all_pixels(test1, 0);
+ assign_all_pixels(test2, 0);
+ assign_all_pixels(test1_i, 0);
+ assign_all_pixels(test2_i, 0);
+
+ for (int i = 0; i < 10; ++i)
+ {
+ const long width = rnd.get_random_32bit_number()%10 + 1;
+ const long height = rnd.get_random_32bit_number()%10 + 1;
+ const point p(rnd.get_random_32bit_number()%img.nc(),
+ rnd.get_random_32bit_number()%img.nr());
+
+ const rectangle rect = centered_rect(p, width, height);
+ sum_filter(img, test1, rect);
+ sum_filter(img, test2, rect);
+ sum_filter(img, test1_i, rect);
+ sum_filter(img, test2_i, rect);
+
+ DLIB_TEST(mat(test1) == mat(test1_i));
+ DLIB_TEST(mat(test2) == mat(test2_i));
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type1,
+ typename image_type2
+ >
+ void naive_max_filter (
+ const image_type1& img,
+ image_type2& out,
+ const long width,
+ const long height,
+ typename image_type1::type thresh
+ )
+ {
+ const rectangle area = get_rect(img);
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ const rectangle win = centered_rect(point(c,r),width,height).intersect(area);
+ out[r][c] += std::max(dlib::max(subm(mat(img),win)), thresh);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_max_filter(long rows, long cols, long width, long height, dlib::rand& rnd)
+ {
+ array2d<int> img(rows, cols);
+ rectangle rect = centered_rect(0,0, width, height);
+
+ array2d<int> out(img.nr(),img.nc());
+ assign_all_pixels(out, 0);
+ array2d<int> out2(img.nr(),img.nc());
+ assign_all_pixels(out2, 0);
+
+ for (long r = 0; r < img.nr(); ++r)
+ {
+ for (long c = 0; c < img.nc(); ++c)
+ {
+ img[r][c] = rnd.get_random_32bit_number();
+ }
+ }
+
+ const int thresh = rnd.get_random_32bit_number();
+
+ naive_max_filter(img, out2, rect.width(), rect.height(), thresh);
+ max_filter(img, out, rect.width(), rect.height(), thresh);
+
+ DLIB_TEST_MSG(mat(out) == mat(out2),
+ "rows: "<< rows
+ << "\ncols: "<< rows
+ << "\nwidth: "<< width
+ << "\nheight: "<< height );
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_max_filter()
+ {
+ dlib::rand rnd;
+ for (int iter = 0; iter < 300; ++iter)
+ {
+ print_spinner();
+ test_max_filter(0,0,1,1,rnd);
+ test_max_filter(0,0,3,1,rnd);
+ test_max_filter(0,0,3,3,rnd);
+ test_max_filter(0,0,1,3,rnd);
+ test_max_filter(1,1,1,1,rnd);
+ test_max_filter(2,2,1,1,rnd);
+ test_max_filter(3,3,1,1,rnd);
+ test_max_filter(3,3,3,3,rnd);
+ test_max_filter(3,3,2,2,rnd);
+ test_max_filter(3,3,3,5,rnd);
+ test_max_filter(3,3,6,8,rnd);
+ test_max_filter(20,20,901,901,rnd);
+ test_max_filter(5,5,1,5,rnd);
+ test_max_filter(50,50,9,9,rnd);
+ test_max_filter(50,50,9,9,rnd);
+ test_max_filter(50,50,10,10,rnd);
+ test_max_filter(50,50,11,10,rnd);
+ test_max_filter(50,50,10,11,rnd);
+ test_max_filter(50,50,10,21,rnd);
+ test_max_filter(50,50,20,10,rnd);
+ test_max_filter(50,50,20,10,rnd);
+ test_max_filter(50,50,9,9,rnd);
+ test_max_filter(20,20,1,901,rnd);
+ test_max_filter(20,20,3,901,rnd);
+ test_max_filter(20,20,901,1,rnd);
+ }
+
+ for (int iter = 0; iter < 200; ++iter)
+ {
+ print_spinner();
+ test_max_filter((int)rnd.get_random_8bit_number()%100+1,
+ (int)rnd.get_random_8bit_number()%100+1,
+ (int)rnd.get_random_8bit_number()%150+1,
+ (int)rnd.get_random_8bit_number()%150+1,
+ rnd);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void make_images (
+ dlib::rand& rnd,
+ array<array2d<unsigned char> >& images,
+ long num,
+ long nr,
+ long nc
+ )
+ {
+ images.resize(num);
+ for (unsigned long i = 0; i < images.size(); ++i)
+ {
+ images[i].set_size(nr,nc);
+ }
+
+ for (unsigned long i = 0; i < images.size(); ++i)
+ {
+ for (long r = 0; r < nr; ++r)
+ {
+ for (long c = 0; c < nc; ++c)
+ {
+ images[i][r][c] = rnd.get_random_8bit_number();
+ }
+ }
+ }
+ }
+
+
+ template <
+ typename image_array_type
+ >
+ void brute_force_scan_image_movable_parts (
+ std::vector<std::pair<double, point> >& dets,
+ const image_array_type& images,
+ const rectangle& window,
+ const std::vector<std::pair<unsigned int, rectangle> >& fixed_rects,
+ const std::vector<std::pair<unsigned int, rectangle> >& movable_rects,
+ const double thresh,
+ const unsigned long
+ )
+ {
+ dets.clear();
+ if (movable_rects.size() == 0 && fixed_rects.size() == 0)
+ return;
+
+ for (long r = 0; r < images[0].nr(); ++r)
+ {
+ for (long c = 0; c < images[0].nc(); ++c)
+ {
+ const point p(c,r);
+ double score = sum_of_rects_in_images_movable_parts(images,
+ window,
+ fixed_rects,
+ movable_rects,
+ p);
+
+ if (score >= thresh)
+ {
+ dets.push_back(make_pair(score,p));
+ }
+ }
+ }
+ }
+
+ void test_scan_images_movable_parts()
+ {
+ array<array2d<unsigned char> > images;
+ dlib::rand rnd;
+ for (int iter = 0; iter < 40; ++iter)
+ {
+ print_spinner();
+ const int num_images = rnd.get_random_32bit_number()%4+1;
+
+ make_images(rnd,images, num_images,
+ rnd.get_random_32bit_number()%50+1,
+ rnd.get_random_32bit_number()%50+1
+ );
+
+ std::vector<std::pair<double,point> > dets1, dets2;
+ std::vector<std::pair<unsigned int, rectangle> > fixed_rects, movable_rects;
+
+ double total_area = 0;
+ for (unsigned long i = 0; i < images.size(); ++i)
+ {
+ fixed_rects.push_back(make_pair(i, centered_rect(
+ rnd.get_random_32bit_number()%10-5,
+ rnd.get_random_32bit_number()%10-5,
+ rnd.get_random_32bit_number()%10,
+ rnd.get_random_32bit_number()%10
+ )));
+
+ total_area += fixed_rects.back().second.area();
+
+ movable_rects.push_back(make_pair(i, centered_rect(
+ 0,
+ 0,
+ rnd.get_random_32bit_number()%10+1,
+ rnd.get_random_32bit_number()%10+1
+ )));
+ total_area += movable_rects.back().second.area();
+ }
+
+ const rectangle window = centered_rect(0,0,
+ rnd.get_random_32bit_number()%15+1,
+ rnd.get_random_32bit_number()%15+1);
+ dlog << LINFO << "window size: "<< window.width() << ", " << window.height();
+ const double thresh = total_area*130;
+ const unsigned long max_dets = get_rect(images[0]).area();
+
+ scan_image_movable_parts(dets1,images,window,fixed_rects,movable_rects,thresh, max_dets);
+ brute_force_scan_image_movable_parts(dets2,images,window,fixed_rects,movable_rects,thresh, max_dets);
+
+ dlog << LINFO << "max_possible dets: " << max_dets;
+ dlog << LINFO << "regular dets: " << dets1.size();
+ dlog << LINFO << "brute force: " << dets2.size();
+ DLIB_TEST(dets1.size() == dets2.size());
+
+ array2d<double> check(images[0].nr(), images[0].nc());
+ assign_all_pixels(check, 1e-300);
+ for (unsigned long i = 0; i < dets1.size(); ++i)
+ {
+ const point p = dets1[i].second;
+ check[p.y()][p.x()] = dets1[i].first;
+ }
+ for (unsigned long i = 0; i < dets2.size(); ++i)
+ {
+ const point p = dets2[i].second;
+ DLIB_TEST(std::abs(check[p.y()][p.x()] - dets2[i].first) < 1e-10);
+ }
+ dlog << LINFO << "=======================\n";
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class scan_image_tester : public tester
+ {
+ public:
+ scan_image_tester (
+ ) :
+ tester ("test_scan_image",
+ "Runs tests on the scan_image routine.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_scan_images_movable_parts();
+ test_max_filter();
+
+ run_test1();
+ run_test2();
+ run_test3<unsigned char>(1);
+ run_test3<unsigned char>(-1);
+ run_test3<double>(1);
+ run_test3<double>(-1);
+
+ test_sum_filter<unsigned char>();
+ test_sum_filter<double>();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/sequence.cpp b/ml/dlib/dlib/test/sequence.cpp
new file mode 100644
index 000000000..ffa6efdb8
--- /dev/null
+++ b/ml/dlib/dlib/test/sequence.cpp
@@ -0,0 +1,312 @@
+// Copyright (C) 2004 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/sequence.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.sequence");
+
+ template <
+ typename seq
+ >
+ void sequence_sort_test (
+ )
+ /*!
+ requires
+ - seq is an implementation of sequence/sequence_sort_aseqract.h is instantiated
+ with int
+ ensures
+ - runs tests on seq for compliance with the specs
+ !*/
+ {
+
+
+ srand(static_cast<unsigned int>(time(0)));
+
+
+ print_spinner();
+
+
+
+
+
+ {
+ // this test is to make sure that jumping around via
+ // operator[] doesn't corrupt the object
+
+ seq a;
+
+ for (int i = 0; i < 100; ++i)
+ {
+ int x = i;
+ a.add(a.size(),x);
+ }
+
+
+ int x = 0;
+
+ for (int i = 0; i < (int)a.size(); ++i)
+ {
+ DLIB_TEST_MSG(a[i] >= i,"1");
+ // cout << a[i] << endl;
+ }
+
+ for (unsigned long i = 0; i < a.size(); ++i)
+ {
+ for (unsigned long j = i+1; j < a.size(); ++j)
+ {
+ if ((a[j]+a[i])%3 ==0)
+ {
+ a.remove(j,x);
+ --j;
+ }
+ }
+ }
+
+ //cout << endl;
+
+ for (int i = 0; i < (int)a.size(); ++i)
+ {
+ // cout << a[i] << endl;
+ DLIB_TEST_MSG(a[i] >= i,"2");
+ }
+
+ }
+
+
+
+
+
+
+
+ seq test, test2;
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ enumerable<int>& e = test;
+
+ DLIB_TEST(e.at_start() == true);
+ DLIB_TEST(e.current_element_valid() == false);
+
+
+ for (int g = 0; g < 5; ++g)
+ {
+ test.clear();
+ test2.clear();
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(e.at_start() == true);
+ DLIB_TEST(e.current_element_valid() == false);
+
+ DLIB_TEST(e.move_next() == false);
+ DLIB_TEST(e.current_element_valid() == false);
+ DLIB_TEST(e.at_start() == false);
+ DLIB_TEST(test.at_start() == false);
+ swap(test,test2);
+ DLIB_TEST(test.at_start() == true);
+ test.clear();
+ test2.clear();
+
+ int a;
+
+
+ for (int i = 0; i < 100; ++i)
+ {
+ a = i;
+ test.add(i,a);
+ }
+
+ DLIB_TEST(test.size() == 100);
+
+ for (int i = 0; i < static_cast<int>(test.size()); ++i)
+ {
+ DLIB_TEST(test[i] == i);
+ }
+
+ swap(test,test2);
+
+ a = 0;
+ DLIB_TEST(test2.at_start() == true);
+ while(test2.move_next())
+ {
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.element() == a);
+ ++a;
+ }
+
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+
+ test2.reset();
+
+ DLIB_TEST(test2.at_start() == true);
+ DLIB_TEST(test2.current_element_valid() == false);
+
+ a = 0;
+ while(test2.move_next())
+ {
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == true);
+ DLIB_TEST(test2.element() == a);
+ ++a;
+ }
+
+
+
+
+
+ for (int i = 0; i < 1000; ++i)
+ {
+ a = ::rand();
+ test.add(0,a);
+ }
+ DLIB_TEST(test.size() == 1000);
+
+ test.sort();
+
+
+ for (unsigned long i = 0; i < test.size()-1; ++i)
+ {
+ DLIB_TEST(test[i] <= test[i+1]);
+ }
+
+ a = 0;
+ while(test.move_next())
+ {
+ DLIB_TEST(a <= test.element());
+ a = test.element();
+ }
+
+
+ test.clear();
+ test2.clear();
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test2.size() == 0);
+
+ for (int i = 0; i < 100; ++i)
+ {
+ a = i;
+ test.add(i,a);
+ }
+
+ for (int i = 100; i < 200; ++i)
+ {
+ a = i;
+ test.add(i,a);
+ }
+
+ test.cat(test2);
+ DLIB_TEST(test.size() == 200);
+ DLIB_TEST(test2.size() == 0);
+
+
+ // serialize the state of test, then clear test, then
+ // load the state back into test.
+ ostringstream sout;
+ serialize(test,sout);
+ DLIB_TEST(test.at_start() == true);
+ istringstream sin(sout.str());
+ test.clear();
+ deserialize(test,sin);
+
+
+ for (int i = 0; i < 200; ++i)
+ {
+ DLIB_TEST(test[i] == i);
+ }
+
+ a = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element() == a);
+ DLIB_TEST(test[0]==0);
+ ++a;
+ }
+
+ DLIB_TEST(a == 200);
+
+ DLIB_TEST(test[9] == 9);
+ test.remove(9,a);
+ DLIB_TEST(a == 9);
+ DLIB_TEST(test[9] == 10);
+ DLIB_TEST(test.size() == 199);
+
+ test.remove(0,a);
+ DLIB_TEST(test[0] == 1);
+ DLIB_TEST(test.size() == 198);
+ DLIB_TEST(a == 0);
+ DLIB_TEST(test[9] == 11);
+ DLIB_TEST(test[20] == 22);
+
+
+
+
+ }
+
+ {
+ test.clear();
+ for (int i = 0; i < 100; ++i)
+ {
+ int a = 3;
+ test.add(0,a);
+ }
+ DLIB_TEST(test.size() == 100);
+ remover<int>& go = test;
+ for (int i = 0; i < 100; ++i)
+ {
+ int a = 9;
+ go.remove_any(a);
+ DLIB_TEST(a == 3);
+ }
+ DLIB_TEST(go.size() == 0);
+ }
+
+
+ }
+
+
+
+
+ class sequence_tester : public tester
+ {
+ public:
+ sequence_tester (
+ ) :
+ tester ("test_sequence",
+ "Runs tests on the sequence component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing sort_1a";
+ sequence_sort_test<sequence<int>::sort_1a> ();
+ dlog << LINFO << "testing sort_1a_c";
+ sequence_sort_test<sequence<int>::sort_1a_c>();
+ dlog << LINFO << "testing sort_2a";
+ sequence_sort_test<sequence<int>::sort_2a> ();
+ dlog << LINFO << "testing sort_2a_c";
+ sequence_sort_test<sequence<int>::sort_2a_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/sequence_labeler.cpp b/ml/dlib/dlib/test/sequence_labeler.cpp
new file mode 100644
index 000000000..4002d6821
--- /dev/null
+++ b/ml/dlib/dlib/test/sequence_labeler.cpp
@@ -0,0 +1,461 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+#include <dlib/rand.h>
+
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.sequence_labeler");
+
+// ----------------------------------------------------------------------------------------
+
+ const unsigned long num_label_states = 3; // the "hidden" states
+ const unsigned long num_sample_states = 3;
+
+// ----------------------------------------------------------------------------------------
+
+ struct funny_sequence
+ {
+ std::vector<unsigned long> item;
+ unsigned long size() const { return item.size(); }
+ };
+ funny_sequence make_funny_sequence(const std::vector<unsigned long>& item)
+ {
+ funny_sequence temp;
+ temp.item = item;
+ return temp;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class feature_extractor
+ {
+ public:
+ typedef funny_sequence sequence_type;
+
+ unsigned long num_features() const
+ {
+ return num_label_states*num_label_states + num_label_states*num_sample_states;
+ }
+
+ unsigned long order() const
+ {
+ return 1;
+ }
+
+ unsigned long num_labels() const
+ {
+ return num_label_states;
+ }
+
+ template <typename feature_setter, typename EXP>
+ void get_features (
+ feature_setter& set_feature,
+ const sequence_type& x,
+ const matrix_exp<EXP>& y,
+ unsigned long position
+ ) const
+ {
+ if (y.size() > 1)
+ set_feature(y(1)*num_label_states + y(0));
+
+ set_feature(num_label_states*num_label_states +
+ y(0)*num_sample_states + x.item[position]);
+ }
+ };
+
+ class feature_extractor_partial
+ {
+ public:
+ typedef funny_sequence sequence_type;
+
+ unsigned long num_features() const
+ {
+ return num_label_states*num_label_states + num_label_states*num_sample_states;
+ }
+
+ unsigned long order() const
+ {
+ return 1;
+ }
+
+ unsigned long num_labels() const
+ {
+ return num_label_states;
+ }
+
+ template <typename feature_setter, typename EXP>
+ void get_features (
+ feature_setter& set_feature,
+ const sequence_type& x,
+ const matrix_exp<EXP>& y,
+ unsigned long position
+ ) const
+ {
+ if (y.size() > 1)
+ {
+ set_feature(y(1)*num_label_states + y(0), 0.5);
+ set_feature(y(1)*num_label_states + y(0), 0.5);
+ }
+
+ set_feature(num_label_states*num_label_states +
+ y(0)*num_sample_states + x.item[position],0.25);
+ set_feature(num_label_states*num_label_states +
+ y(0)*num_sample_states + x.item[position],0.75);
+ }
+ };
+
+ bool called_rejct_labeling = false;
+ class feature_extractor2
+ {
+ public:
+ typedef funny_sequence sequence_type;
+
+ unsigned long num_features() const
+ {
+ return num_label_states*num_label_states + num_label_states*num_sample_states;
+ }
+
+ unsigned long order() const
+ {
+ return 1;
+ }
+
+ unsigned long num_labels() const
+ {
+ return num_label_states;
+ }
+
+ template <typename EXP>
+ bool reject_labeling (
+ const sequence_type& ,
+ const matrix_exp<EXP>& ,
+ unsigned long
+ ) const
+ {
+ called_rejct_labeling = true;
+ return false;
+ }
+
+ template <typename feature_setter, typename EXP>
+ void get_features (
+ feature_setter& set_feature,
+ const sequence_type& x,
+ const matrix_exp<EXP>& y,
+ unsigned long position
+ ) const
+ {
+ if (y.size() > 1)
+ set_feature(y(1)*num_label_states + y(0));
+
+ set_feature(num_label_states*num_label_states +
+ y(0)*num_sample_states + x.item[position]);
+ }
+ };
+
+ void serialize(const feature_extractor&, std::ostream&) {}
+ void deserialize(feature_extractor&, std::istream&) {}
+ void serialize(const feature_extractor2&, std::ostream&) {}
+ void deserialize(feature_extractor2&, std::istream&) {}
+
+// ----------------------------------------------------------------------------------------
+
+ void sample_hmm (
+ dlib::rand& rnd,
+ const matrix<double>& transition_probabilities,
+ const matrix<double>& emission_probabilities,
+ unsigned long previous_label,
+ unsigned long& next_label,
+ unsigned long& next_sample
+ )
+ /*!
+ requires
+ - previous_label < transition_probabilities.nr()
+ - transition_probabilities.nr() == transition_probabilities.nc()
+ - transition_probabilities.nr() == emission_probabilities.nr()
+ - The rows of transition_probabilities and emission_probabilities must sum to 1.
+ (i.e. sum_cols(transition_probabilities) and sum_cols(emission_probabilities)
+ must evaluate to vectors of all 1s.)
+ ensures
+ - This function randomly samples the HMM defined by transition_probabilities
+ and emission_probabilities assuming that the previous hidden state
+ was previous_label.
+ - The HMM is defined by:
+ - P(next_label |previous_label) == transition_probabilities(previous_label, next_label)
+ - P(next_sample|next_label) == emission_probabilities (next_label, next_sample)
+ - #next_label == the sampled value of the hidden state
+ - #next_sample == the sampled value of the observed state
+ !*/
+ {
+ // sample next_label
+ double p = rnd.get_random_double();
+ for (long c = 0; p >= 0 && c < transition_probabilities.nc(); ++c)
+ {
+ next_label = c;
+ p -= transition_probabilities(previous_label, c);
+ }
+
+ // now sample next_sample
+ p = rnd.get_random_double();
+ for (long c = 0; p >= 0 && c < emission_probabilities.nc(); ++c)
+ {
+ next_sample = c;
+ p -= emission_probabilities(next_label, c);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void make_dataset (
+ const matrix<double>& transition_probabilities,
+ const matrix<double>& emission_probabilities,
+ std::vector<funny_sequence>& samples,
+ std::vector<std::vector<unsigned long> >& labels,
+ unsigned long dataset_size
+ )
+ /*!
+ requires
+ - transition_probabilities.nr() == transition_probabilities.nc()
+ - transition_probabilities.nr() == emission_probabilities.nr()
+ - The rows of transition_probabilities and emission_probabilities must sum to 1.
+ (i.e. sum_cols(transition_probabilities) and sum_cols(emission_probabilities)
+ must evaluate to vectors of all 1s.)
+ ensures
+ - This function randomly samples a bunch of sequences from the HMM defined by
+ transition_probabilities and emission_probabilities.
+ - The HMM is defined by:
+ - The probability of transitioning from hidden state H1 to H2
+ is given by transition_probabilities(H1,H2).
+ - The probability of a hidden state H producing an observed state
+ O is given by emission_probabilities(H,O).
+ - #samples.size() == labels.size() == dataset_size
+ - for all valid i:
+ - #labels[i] is a randomly sampled sequence of hidden states from the
+ given HMM. #samples[i] is its corresponding randomly sampled sequence
+ of observed states.
+ !*/
+ {
+ samples.clear();
+ labels.clear();
+
+ dlib::rand rnd;
+
+ // now randomly sample some labeled sequences from our Hidden Markov Model
+ for (unsigned long iter = 0; iter < dataset_size; ++iter)
+ {
+ const unsigned long sequence_size = rnd.get_random_32bit_number()%20+3;
+ std::vector<unsigned long> sample(sequence_size);
+ std::vector<unsigned long> label(sequence_size);
+
+ unsigned long previous_label = rnd.get_random_32bit_number()%num_label_states;
+ for (unsigned long i = 0; i < sample.size(); ++i)
+ {
+ unsigned long next_label=0, next_sample=0;
+ sample_hmm(rnd, transition_probabilities, emission_probabilities,
+ previous_label, next_label, next_sample);
+
+ label[i] = next_label;
+ sample[i] = next_sample;
+
+ previous_label = next_label;
+ }
+
+ samples.push_back(make_funny_sequence(sample));
+ labels.push_back(label);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename fe_type>
+ void do_test()
+ {
+ called_rejct_labeling = false;
+
+ matrix<double> transition_probabilities(num_label_states, num_label_states);
+ transition_probabilities = 0.05, 0.90, 0.05,
+ 0.05, 0.05, 0.90,
+ 0.90, 0.05, 0.05;
+
+ matrix<double> emission_probabilities(num_label_states,num_sample_states);
+ emission_probabilities = 0.5, 0.5, 0.0,
+ 0.0, 0.5, 0.5,
+ 0.5, 0.0, 0.5;
+
+ print_spinner();
+
+
+ std::vector<funny_sequence> samples;
+ std::vector<std::vector<unsigned long> > labels;
+ make_dataset(transition_probabilities,emission_probabilities,
+ samples, labels, 1000);
+
+ dlog << LINFO << "samples.size(): "<< samples.size();
+
+ // print out some of the randomly sampled sequences
+ for (int i = 0; i < 10; ++i)
+ {
+ dlog << LINFO << "hidden states: " << trans(mat(labels[i]));
+ dlog << LINFO << "observed states: " << trans(mat(samples[i].item));
+ dlog << LINFO << "******************************";
+ }
+
+ print_spinner();
+ structural_sequence_labeling_trainer<fe_type> trainer;
+ trainer.set_c(4);
+ DLIB_TEST(trainer.get_c() == 4);
+ trainer.set_num_threads(4);
+ DLIB_TEST(trainer.get_num_threads() == 4);
+
+
+
+ // Learn to do sequence labeling from the dataset
+ sequence_labeler<fe_type> labeler = trainer.train(samples, labels);
+
+ std::vector<unsigned long> predicted_labels = labeler(samples[0]);
+ dlog << LINFO << "true hidden states: "<< trans(mat(labels[0]));
+ dlog << LINFO << "predicted hidden states: "<< trans(mat(predicted_labels));
+
+ DLIB_TEST(mat(labels[0]) == mat(predicted_labels));
+
+
+ print_spinner();
+
+
+ // We can also do cross-validation
+ matrix<double> confusion_matrix;
+ confusion_matrix = cross_validate_sequence_labeler(trainer, samples, labels, 4);
+ dlog << LINFO << "cross-validation: ";
+ dlog << LINFO << confusion_matrix;
+ double accuracy = sum(diag(confusion_matrix))/sum(confusion_matrix);
+ dlog << LINFO << "label accuracy: "<< accuracy;
+ DLIB_TEST(std::abs(accuracy - 0.882) < 0.01);
+
+ print_spinner();
+
+
+ matrix<double,0,1> true_hmm_model_weights = log(join_cols(reshape_to_column_vector(transition_probabilities),
+ reshape_to_column_vector(emission_probabilities)));
+
+ sequence_labeler<fe_type> labeler_true(true_hmm_model_weights);
+
+ confusion_matrix = test_sequence_labeler(labeler_true, samples, labels);
+ dlog << LINFO << "True HMM model: ";
+ dlog << LINFO << confusion_matrix;
+ accuracy = sum(diag(confusion_matrix))/sum(confusion_matrix);
+ dlog << LINFO << "label accuracy: "<< accuracy;
+ DLIB_TEST(std::abs(accuracy - 0.882) < 0.01);
+
+
+
+ print_spinner();
+
+
+
+
+ // Finally, the labeler can be serialized to disk just like most dlib objects.
+ ostringstream sout;
+ serialize(labeler, sout);
+
+ sequence_labeler<fe_type> labeler2;
+ // recall from disk
+ istringstream sin(sout.str());
+ deserialize(labeler2, sin);
+ confusion_matrix = test_sequence_labeler(labeler2, samples, labels);
+ dlog << LINFO << "deserialized labeler: ";
+ dlog << LINFO << confusion_matrix;
+ accuracy = sum(diag(confusion_matrix))/sum(confusion_matrix);
+ dlog << LINFO << "label accuracy: "<< accuracy;
+ DLIB_TEST(std::abs(accuracy - 0.882) < 0.01);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test2()
+ {
+ /*
+ The point of this test is to make sure calling set_feature() multiple
+ times works the way it is supposed to.
+ */
+
+ print_spinner();
+ std::vector<funny_sequence> samples;
+ std::vector<std::vector<unsigned long> > labels;
+
+ matrix<double> transition_probabilities(num_label_states, num_label_states);
+ transition_probabilities = 0.05, 0.90, 0.05,
+ 0.05, 0.05, 0.90,
+ 0.90, 0.05, 0.05;
+
+ matrix<double> emission_probabilities(num_label_states,num_sample_states);
+ emission_probabilities = 0.5, 0.5, 0.0,
+ 0.0, 0.5, 0.5,
+ 0.5, 0.0, 0.5;
+
+
+ make_dataset(transition_probabilities,emission_probabilities,
+ samples, labels, 1000);
+
+ dlog << LINFO << "samples.size(): "<< samples.size();
+
+ structural_sequence_labeling_trainer<feature_extractor> trainer;
+ structural_sequence_labeling_trainer<feature_extractor_partial> trainer_part;
+ trainer.set_c(4);
+ trainer_part.set_c(4);
+ trainer.set_num_threads(4);
+ trainer_part.set_num_threads(4);
+ trainer.set_epsilon(1e-8);
+ trainer_part.set_epsilon(1e-8);
+
+
+
+ // Learn to do sequence labeling from the dataset
+ sequence_labeler<feature_extractor> labeler = trainer.train(samples, labels);
+ sequence_labeler<feature_extractor_partial> labeler_part = trainer_part.train(samples, labels);
+
+ dlog << LINFO << "weight disagreement: "<< max(abs(labeler.get_weights() - labeler_part.get_weights()));
+ dlog << LINFO << "max weight magnitude: "<< max(abs(labeler.get_weights()));
+
+ // Both feature extractors should be equivalent.
+ DLIB_TEST(max(abs(labeler.get_weights() - labeler_part.get_weights())) < 1e-6);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class sequence_labeler_tester : public tester
+ {
+ public:
+ sequence_labeler_tester (
+ ) :
+ tester ("test_sequence_labeler",
+ "Runs tests on the sequence labeling code.")
+ {}
+
+ void perform_test (
+ )
+ {
+ do_test<feature_extractor>();
+ DLIB_TEST(called_rejct_labeling == false);
+ do_test<feature_extractor2>();
+ DLIB_TEST(called_rejct_labeling == true);
+
+ test2();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/sequence_segmenter.cpp b/ml/dlib/dlib/test/sequence_segmenter.cpp
new file mode 100644
index 000000000..acdcd69be
--- /dev/null
+++ b/ml/dlib/dlib/test/sequence_segmenter.cpp
@@ -0,0 +1,294 @@
+// Copyright (C) 2013 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+#include <dlib/rand.h>
+
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.sequence_segmenter");
+
+// ----------------------------------------------------------------------------------------
+
+ dlib::rand rnd;
+
+ template <bool use_BIO_model_, bool use_high_order_features_, bool allow_negative_weights_>
+ class unigram_extractor
+ {
+ public:
+
+ const static bool use_BIO_model = use_BIO_model_;
+ const static bool use_high_order_features = use_high_order_features_;
+ const static bool allow_negative_weights = allow_negative_weights_;
+
+ typedef std::vector<unsigned long> sequence_type;
+
+ std::map<unsigned long, matrix<double,0,1> > feats;
+
+ unigram_extractor()
+ {
+ matrix<double,0,1> v1, v2, v3;
+ v1 = randm(num_features(), 1, rnd);
+ v2 = randm(num_features(), 1, rnd);
+ v3 = randm(num_features(), 1, rnd);
+ v1(0) = 1;
+ v2(1) = 1;
+ v3(2) = 1;
+ v1(3) = -1;
+ v2(4) = -1;
+ v3(5) = -1;
+ for (unsigned long i = 0; i < num_features(); ++i)
+ {
+ if ( i < 3)
+ feats[i] = v1;
+ else if (i < 6)
+ feats[i] = v2;
+ else
+ feats[i] = v3;
+ }
+ }
+
+ unsigned long num_features() const { return 10; }
+ unsigned long window_size() const { return 3; }
+
+ template <typename feature_setter>
+ void get_features (
+ feature_setter& set_feature,
+ const sequence_type& x,
+ unsigned long position
+ ) const
+ {
+ const matrix<double,0,1>& m = feats.find(x[position])->second;
+ for (unsigned long i = 0; i < num_features(); ++i)
+ {
+ set_feature(i, m(i));
+ }
+ }
+
+ };
+
+ template <bool use_BIO_model_, bool use_high_order_features_, bool neg>
+ void serialize(const unigram_extractor<use_BIO_model_,use_high_order_features_,neg>& item , std::ostream& out )
+ {
+ serialize(item.feats, out);
+ }
+
+ template <bool use_BIO_model_, bool use_high_order_features_, bool neg>
+ void deserialize(unigram_extractor<use_BIO_model_,use_high_order_features_,neg>& item, std::istream& in)
+ {
+ deserialize(item.feats, in);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void make_dataset (
+ std::vector<std::vector<unsigned long> >& samples,
+ std::vector<std::vector<unsigned long> >& labels,
+ unsigned long dataset_size
+ )
+ {
+ samples.clear();
+ labels.clear();
+
+ samples.resize(dataset_size);
+ labels.resize(dataset_size);
+
+
+ unigram_extractor<true,true,true> fe;
+ dlib::rand rnd;
+
+ for (unsigned long iter = 0; iter < dataset_size; ++iter)
+ {
+
+ samples[iter].resize(10);
+ labels[iter].resize(10);
+
+ for (unsigned long i = 0; i < samples[iter].size(); ++i)
+ {
+ samples[iter][i] = rnd.get_random_32bit_number()%fe.num_features();
+ if (samples[iter][i] < 3)
+ {
+ labels[iter][i] = impl_ss::BEGIN;
+ }
+ else if (samples[iter][i] < 6)
+ {
+ labels[iter][i] = impl_ss::INSIDE;
+ }
+ else
+ {
+ labels[iter][i] = impl_ss::OUTSIDE;
+ }
+
+ if (i != 0)
+ {
+ // do rejection sampling to avoid impossible labels
+ if (labels[iter][i] == impl_ss::INSIDE &&
+ labels[iter][i-1] == impl_ss::OUTSIDE)
+ {
+ --i;
+ }
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void make_dataset2 (
+ std::vector<std::vector<unsigned long> >& samples,
+ std::vector<std::vector<std::pair<unsigned long, unsigned long> > >& segments,
+ unsigned long dataset_size
+ )
+ {
+ segments.clear();
+ std::vector<std::vector<unsigned long> > labels;
+ make_dataset(samples, labels, dataset_size);
+ segments.resize(samples.size());
+
+ // Convert from BIO tagging to the explicit segments representation.
+ for (unsigned long k = 0; k < labels.size(); ++k)
+ {
+ for (unsigned long i = 0; i < labels[k].size(); ++i)
+ {
+ if (labels[k][i] == impl_ss::BEGIN)
+ {
+ const unsigned long begin = i;
+ ++i;
+ while (i < labels[k].size() && labels[k][i] == impl_ss::INSIDE)
+ ++i;
+
+ segments[k].push_back(std::make_pair(begin, i));
+ --i;
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <bool use_BIO_model, bool use_high_order_features, bool allow_negative_weights>
+ void do_test()
+ {
+ dlog << LINFO << "use_BIO_model: "<< use_BIO_model;
+ dlog << LINFO << "use_high_order_features: "<< use_high_order_features;
+ dlog << LINFO << "allow_negative_weights: "<< allow_negative_weights;
+
+ std::vector<std::vector<unsigned long> > samples;
+ std::vector<std::vector<std::pair<unsigned long,unsigned long> > > segments;
+ make_dataset2( samples, segments, 100);
+
+ print_spinner();
+ typedef unigram_extractor<use_BIO_model,use_high_order_features,allow_negative_weights> fe_type;
+
+ fe_type fe_temp;
+ fe_type fe_temp2;
+ structural_sequence_segmentation_trainer<fe_type> trainer(fe_temp2);
+ trainer.set_c(5);
+ trainer.set_num_threads(1);
+
+
+ sequence_segmenter<fe_type> labeler = trainer.train(samples, segments);
+
+ print_spinner();
+
+ const std::vector<std::pair<unsigned long, unsigned long> > predicted_labels = labeler(samples[1]);
+ const std::vector<std::pair<unsigned long, unsigned long> > true_labels = segments[1];
+ /*
+ for (unsigned long i = 0; i < predicted_labels.size(); ++i)
+ cout << "["<<predicted_labels[i].first<<","<<predicted_labels[i].second<<") ";
+ cout << endl;
+ for (unsigned long i = 0; i < true_labels.size(); ++i)
+ cout << "["<<true_labels[i].first<<","<<true_labels[i].second<<") ";
+ cout << endl;
+ */
+
+ DLIB_TEST(predicted_labels.size() > 0);
+ DLIB_TEST(predicted_labels.size() == true_labels.size());
+ for (unsigned long i = 0; i < predicted_labels.size(); ++i)
+ {
+ DLIB_TEST(predicted_labels[i].first == true_labels[i].first);
+ DLIB_TEST(predicted_labels[i].second == true_labels[i].second);
+ }
+
+
+ matrix<double> res;
+
+ res = cross_validate_sequence_segmenter(trainer, samples, segments, 3);
+ dlog << LINFO << "cv res: "<< res;
+ DLIB_TEST(min(res) > 0.98);
+ make_dataset2( samples, segments, 100);
+ res = test_sequence_segmenter(labeler, samples, segments);
+ dlog << LINFO << "test res: "<< res;
+ DLIB_TEST(min(res) > 0.98);
+
+ print_spinner();
+
+ ostringstream sout;
+ serialize(labeler, sout);
+ istringstream sin(sout.str());
+ sequence_segmenter<fe_type> labeler2;
+ deserialize(labeler2, sin);
+
+ res = test_sequence_segmenter(labeler2, samples, segments);
+ dlog << LINFO << "test res2: "<< res;
+ DLIB_TEST(min(res) > 0.98);
+
+ long N;
+ if (use_BIO_model)
+ N = 3*3+3;
+ else
+ N = 5*5+5;
+ const double min_normal_weight = min(colm(labeler2.get_weights(), 0, labeler2.get_weights().size()-N));
+ const double min_trans_weight = min(labeler2.get_weights());
+ dlog << LINFO << "min_normal_weight: " << min_normal_weight;
+ dlog << LINFO << "min_trans_weight: " << min_trans_weight;
+ if (allow_negative_weights)
+ {
+ DLIB_TEST(min_normal_weight < 0);
+ DLIB_TEST(min_trans_weight < 0);
+ }
+ else
+ {
+ DLIB_TEST(min_normal_weight == 0);
+ DLIB_TEST(min_trans_weight < 0);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+
+ class unit_test_sequence_segmenter : public tester
+ {
+ public:
+ unit_test_sequence_segmenter (
+ ) :
+ tester ("test_sequence_segmenter",
+ "Runs tests on the sequence segmenting code.")
+ {}
+
+ void perform_test (
+ )
+ {
+ do_test<true,true,false>();
+ do_test<true,false,false>();
+ do_test<false,true,false>();
+ do_test<false,false,false>();
+ do_test<true,true,true>();
+ do_test<true,false,true>();
+ do_test<false,true,true>();
+ do_test<false,false,true>();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/serialize.cpp b/ml/dlib/dlib/test/serialize.cpp
new file mode 100644
index 000000000..f8b3384b9
--- /dev/null
+++ b/ml/dlib/dlib/test/serialize.cpp
@@ -0,0 +1,1087 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <dlib/compress_stream.h>
+#include <dlib/base64.h>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/serialize.h>
+#include <dlib/image_transforms.h>
+
+#include "tester.h"
+
+namespace dlib
+{
+ static bool operator!=(const rgb_pixel& a, const rgb_pixel& b)
+ {
+ return !(a.red==b.red && a.green==b.green && a.blue==b.blue);
+ }
+ static bool operator!=(const bgr_pixel& a, const bgr_pixel& b)
+ {
+ return !(a.red==b.red && a.green==b.green && a.blue==b.blue);
+ }
+
+ static bool operator!=(const hsi_pixel& a, const hsi_pixel& b)
+ {
+ return !(a.h==b.h && a.s==b.s && a.i==b.i);
+ }
+ static bool operator!=(const rgb_alpha_pixel& a, const rgb_alpha_pixel& b)
+ {
+ return !(a.red==b.red && a.green==b.green && a.blue==b.blue && a.alpha==b.alpha);
+ }
+
+}
+
+namespace
+{
+
+// ----------------------------------------------------------------------------------------
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ struct test_object
+ {
+ signed char i1;
+ signed short i2;
+ signed long i3;
+ unsigned char i4;
+ unsigned short i5;
+ unsigned long i6;
+ uint64 i7;
+ int64 i8;
+
+ signed char i1_0;
+ signed short i2_0;
+ signed long i3_0;
+ unsigned char i4_0;
+ unsigned short i5_0;
+ unsigned long i6_0;
+ uint64 i7_0;
+ int64 i8_0;
+
+ signed char i1_n;
+ signed short i2_n;
+ signed long i3_n;
+
+
+ float f1;
+ double f2;
+ long double f3;
+ float f1_inf;
+ double f2_inf;
+ long double f3_inf;
+ float f1_ninf;
+ double f2_ninf;
+ long double f3_ninf;
+ float f1_qnan;
+ double f2_qnan;
+ long double f3_qnan;
+ float f1_snan;
+ double f2_snan;
+ long double f3_snan;
+
+ std::string s1;
+ std::wstring s2;
+
+ int array[10];
+
+ bool b_true;
+ bool b_false;
+
+
+ void set_state_1(
+ )
+ {
+ i1 = 1;
+ i2 = 2;
+ i3 = 3;
+ i4 = 4;
+ i5 = 5;
+ i6 = 6;
+ i7 = 7;
+ i8 = 8;
+
+ i1_0 = 0;
+ i2_0 = 0;
+ i3_0 = 0;
+ i4_0 = 0;
+ i5_0 = 0;
+ i6_0 = 0;
+ i7_0 = 0;
+ i8_0 = 0;
+
+ i1_n = -1;
+ i2_n = -2;
+ i3_n = -3;
+
+ f1 = 123.456f;
+ f2 = 543.341;
+ f3 = 5234234.23;
+
+ f1_inf = numeric_limits<float>::infinity();
+ f2_inf = numeric_limits<double>::infinity();
+ f3_inf = numeric_limits<long double>::infinity();
+ f1_ninf = -numeric_limits<float>::infinity();
+ f2_ninf = -numeric_limits<double>::infinity();
+ f3_ninf = -numeric_limits<long double>::infinity();
+ f1_qnan = numeric_limits<float>::quiet_NaN();
+ f2_qnan = numeric_limits<double>::quiet_NaN();
+ f3_qnan = numeric_limits<long double>::quiet_NaN();
+ f1_snan = numeric_limits<float>::signaling_NaN();
+ f2_snan = numeric_limits<double>::signaling_NaN();
+ f3_snan = numeric_limits<long double>::signaling_NaN();
+
+ s1 = "davis";
+ s2 = L"yo yo yo";
+
+ for (int i = 0; i < 10; ++i)
+ array[i] = i;
+
+ b_true = true;
+ b_false = false;
+ }
+
+ void set_state_2(
+ )
+ {
+ i1 = 10;
+ i2 = 20;
+ i3 = 30;
+ i4 = 40;
+ i5 = 50;
+ i6 = 60;
+ i7 = 70;
+ i8 = 80;
+
+ i1_0 = 5;
+ i2_0 = 6;
+ i3_0 = 7;
+ i4_0 = 8;
+ i5_0 = 9;
+ i6_0 = 10;
+ i7_0 = 11;
+ i8_0 = 12;
+
+ i1_n = -13;
+ i2_n = -25;
+ i3_n = -12;
+
+ f1 = 45.3f;
+ f2 = 0.001;
+ f3 = 2.332;
+
+ f1_inf = f1;
+ f2_inf = f2;
+ f3_inf = f3;
+ f1_ninf = f1;
+ f2_ninf = f2;
+ f3_ninf = f3;
+ f1_qnan = f1;
+ f2_qnan = f2;
+ f3_qnan = f3;
+ f1_snan = f1;
+ f2_snan = f2;
+ f3_snan = f3;
+
+ s1 = "";
+ s2 = L"";
+
+ for (int i = 0; i < 10; ++i)
+ array[i] = 10-i;
+
+ b_true = false;
+ b_false = true;
+ }
+
+ void assert_in_state_1 (
+ )
+ {
+ DLIB_TEST (i1 == 1);
+ DLIB_TEST (i2 == 2);
+ DLIB_TEST (i3 == 3);
+ DLIB_TEST (i4 == 4);
+ DLIB_TEST (i5 == 5);
+ DLIB_TEST (i6 == 6);
+ DLIB_TEST (i7 == 7);
+ DLIB_TEST (i8 == 8);
+
+ DLIB_TEST (i1_0 == 0);
+ DLIB_TEST (i2_0 == 0);
+ DLIB_TEST (i3_0 == 0);
+ DLIB_TEST (i4_0 == 0);
+ DLIB_TEST (i5_0 == 0);
+ DLIB_TEST (i6_0 == 0);
+ DLIB_TEST (i7_0 == 0);
+ DLIB_TEST (i8_0 == 0);
+
+ DLIB_TEST (i1_n == -1);
+ DLIB_TEST (i2_n == -2);
+ DLIB_TEST (i3_n == -3);
+
+ DLIB_TEST (abs(f1 -123.456) < 1e-5);
+ DLIB_TEST (abs(f2 - 543.341) < 1e-10);
+ DLIB_TEST (abs(f3 - 5234234.23) < 1e-10);
+
+ DLIB_TEST (f1_inf == numeric_limits<float>::infinity());
+ DLIB_TEST (f2_inf == numeric_limits<double>::infinity());
+ DLIB_TEST (f3_inf == numeric_limits<long double>::infinity());
+ DLIB_TEST (f1_ninf == -numeric_limits<float>::infinity());
+ DLIB_TEST (f2_ninf == -numeric_limits<double>::infinity());
+ DLIB_TEST (f3_ninf == -numeric_limits<long double>::infinity());
+ DLIB_TEST (!(f1_qnan <= numeric_limits<float>::infinity() && f1_qnan >= -numeric_limits<float>::infinity() ));
+ DLIB_TEST (!(f2_qnan <= numeric_limits<double>::infinity() && f1_qnan >= -numeric_limits<double>::infinity() ));
+ DLIB_TEST (!(f3_qnan <= numeric_limits<long double>::infinity() && f1_qnan >= -numeric_limits<long double>::infinity() ));
+ DLIB_TEST (!(f1_snan <= numeric_limits<float>::infinity() && f1_qnan >= -numeric_limits<float>::infinity() ));
+ DLIB_TEST (!(f2_snan <= numeric_limits<double>::infinity() && f1_qnan >= -numeric_limits<double>::infinity() ));
+ DLIB_TEST (!(f3_snan <= numeric_limits<long double>::infinity() && f1_qnan >= -numeric_limits<long double>::infinity() ));
+
+ DLIB_TEST (s1 == "davis");
+ DLIB_TEST (s2 == L"yo yo yo");
+
+ for (int i = 0; i < 10; ++i)
+ {
+ DLIB_TEST (array[i] == i);
+ }
+
+ DLIB_TEST (b_true == true);
+ DLIB_TEST (b_false == false);
+
+ }
+
+ void assert_in_state_2 (
+ )
+ {
+ DLIB_TEST (i1 == 10);
+ DLIB_TEST (i2 == 20);
+ DLIB_TEST (i3 == 30);
+ DLIB_TEST (i4 == 40);
+ DLIB_TEST (i5 == 50);
+ DLIB_TEST (i6 == 60);
+ DLIB_TEST (i7 == 70);
+ DLIB_TEST (i8 == 80);
+
+ DLIB_TEST (i1_0 == 5);
+ DLIB_TEST (i2_0 == 6);
+ DLIB_TEST (i3_0 == 7);
+ DLIB_TEST (i4_0 == 8);
+ DLIB_TEST (i5_0 == 9);
+ DLIB_TEST (i6_0 == 10);
+ DLIB_TEST (i7_0 == 11);
+ DLIB_TEST (i8_0 == 12);
+
+ DLIB_TEST (i1_n == -13);
+ DLIB_TEST (i2_n == -25);
+ DLIB_TEST (i3_n == -12);
+
+ DLIB_TEST (abs(f1 - 45.3) < 1e-5);
+ DLIB_TEST (abs(f2 - 0.001) < 1e-10);
+ DLIB_TEST (abs(f3 - 2.332) < 1e-10);
+ DLIB_TEST (abs(f1_inf - 45.3) < 1e-5);
+ DLIB_TEST (abs(f2_inf - 0.001) < 1e-10);
+ DLIB_TEST (abs(f3_inf - 2.332) < 1e-10);
+ DLIB_TEST (abs(f1_ninf - 45.3) < 1e-5);
+ DLIB_TEST (abs(f2_ninf - 0.001) < 1e-10);
+ DLIB_TEST (abs(f3_ninf - 2.332) < 1e-10);
+ DLIB_TEST (abs(f1_qnan - 45.3) < 1e-5);
+ DLIB_TEST (abs(f2_qnan - 0.001) < 1e-10);
+ DLIB_TEST (abs(f3_qnan - 2.332) < 1e-10);
+ DLIB_TEST (abs(f1_snan - 45.3) < 1e-5);
+ DLIB_TEST (abs(f2_snan - 0.001) < 1e-10);
+ DLIB_TEST (abs(f3_snan - 2.332) < 1e-10);
+
+ DLIB_TEST (s1 == "");
+ DLIB_TEST (s2 == L"");
+
+ for (int i = 0; i < 10; ++i)
+ {
+ DLIB_TEST (array[i] == 10-i);
+ }
+
+ DLIB_TEST (b_true == false);
+ DLIB_TEST (b_false == true);
+
+ }
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ void serialize (
+ const test_object& item,
+ std::ostream& out
+ )
+ {
+ dlib::serialize(item.i1,out);
+ dlib::serialize(item.i2,out);
+ dlib::serialize(item.i3,out);
+ dlib::serialize(item.i4,out);
+ dlib::serialize(item.i5,out);
+ dlib::serialize(item.i6,out);
+ dlib::serialize(item.i7,out);
+ dlib::serialize(item.i8,out);
+
+ dlib::serialize(item.i1_0,out);
+ dlib::serialize(item.i2_0,out);
+ dlib::serialize(item.i3_0,out);
+ dlib::serialize(item.i4_0,out);
+ dlib::serialize(item.i5_0,out);
+ dlib::serialize(item.i6_0,out);
+ dlib::serialize(item.i7_0,out);
+ dlib::serialize(item.i8_0,out);
+
+ dlib::serialize(item.i1_n,out);
+ dlib::serialize(item.i2_n,out);
+ dlib::serialize(item.i3_n,out);
+
+
+ dlib::serialize(item.f1,out);
+ dlib::serialize(item.f2,out);
+ dlib::serialize(item.f3,out);
+
+ dlib::serialize(item.f1_inf,out);
+ dlib::serialize(item.f2_inf,out);
+ dlib::serialize(item.f3_inf,out);
+ dlib::serialize(item.f1_ninf,out);
+ dlib::serialize(item.f2_ninf,out);
+ dlib::serialize(item.f3_ninf,out);
+ dlib::serialize(item.f1_qnan,out);
+ dlib::serialize(item.f2_qnan,out);
+ dlib::serialize(item.f3_qnan,out);
+ dlib::serialize(item.f1_snan,out);
+ dlib::serialize(item.f2_snan,out);
+ dlib::serialize(item.f3_snan,out);
+
+ dlib::serialize(item.s1,out);
+ dlib::serialize(item.s2,out);
+
+ dlib::serialize(item.array,out);
+
+ dlib::serialize(item.b_true,out);
+ dlib::serialize(item.b_false,out);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void deserialize (
+ test_object& item,
+ std::istream& in
+ )
+ {
+ dlib::deserialize(item.i1,in);
+ dlib::deserialize(item.i2,in);
+ dlib::deserialize(item.i3,in);
+ dlib::deserialize(item.i4,in);
+ dlib::deserialize(item.i5,in);
+ dlib::deserialize(item.i6,in);
+ dlib::deserialize(item.i7,in);
+ dlib::deserialize(item.i8,in);
+
+ dlib::deserialize(item.i1_0,in);
+ dlib::deserialize(item.i2_0,in);
+ dlib::deserialize(item.i3_0,in);
+ dlib::deserialize(item.i4_0,in);
+ dlib::deserialize(item.i5_0,in);
+ dlib::deserialize(item.i6_0,in);
+ dlib::deserialize(item.i7_0,in);
+ dlib::deserialize(item.i8_0,in);
+
+ dlib::deserialize(item.i1_n,in);
+ dlib::deserialize(item.i2_n,in);
+ dlib::deserialize(item.i3_n,in);
+
+
+ dlib::deserialize(item.f1,in);
+ dlib::deserialize(item.f2,in);
+ dlib::deserialize(item.f3,in);
+
+ dlib::deserialize(item.f1_inf,in);
+ dlib::deserialize(item.f2_inf,in);
+ dlib::deserialize(item.f3_inf,in);
+ dlib::deserialize(item.f1_ninf,in);
+ dlib::deserialize(item.f2_ninf,in);
+ dlib::deserialize(item.f3_ninf,in);
+ dlib::deserialize(item.f1_qnan,in);
+ dlib::deserialize(item.f2_qnan,in);
+ dlib::deserialize(item.f3_qnan,in);
+ dlib::deserialize(item.f1_snan,in);
+ dlib::deserialize(item.f2_snan,in);
+ dlib::deserialize(item.f3_snan,in);
+
+ dlib::deserialize(item.s1,in);
+ dlib::deserialize(item.s2,in);
+
+ dlib::deserialize(item.array,in);
+
+ dlib::deserialize(item.b_true,in);
+ dlib::deserialize(item.b_false,in);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'stuff.bin' but using the old
+ // floating point serialization format.
+ const std::string get_decoded_string()
+ {
+ dlib::base64::kernel_1a base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+
+ // The base64 encoded data from the file 'stuff.bin' we want to decode and return.
+ sout << "AVaifX9zEbXa9aocsrcRuvnNrR3WLuuU5eLWiy0UeXmnKXGLKZz8V44gzT4CM6wnCmAHFQug8G3C";
+ sout << "4cuLdNgp2ApkeLcvwFNJRENE0ShrRaxEBFEA8nah7vm8B2VmgImNblCejuP5IcDt60EaCKlqiit8";
+ sout << "+JGrzYxqBm3xFS4P+qlOROdbxc7pXBmUdh0rqNSEvn0FBPdoqY/5SpHgA2yAcH8XFrM1cdu0xS3P";
+ sout << "8PBcmLMJ7bFdzplwhrjuxtm4NfEOi6Rl9sU44AXycYgJd0+uH+dyoI9X3co5b3YWJtjvdVeztNAr";
+ sout << "BfSPfR6oAVNfiMBG7QA=";
+
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+
+ // This function returns the contents of the file 'stuff.bin' but using the new
+ // floating point serialization format.
+ const std::string get_decoded_string2()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'stuff.bin' we want to decode and return.
+ sout << "AVaifX9zEbXa9aocsrcRuvnNqzZLptZ5mRd46xScCIfX6sq/46hG9JwIInElG50EtJKJY/+jAWit";
+ sout << "TpDBWrxBz124JRLsBz62h0D3Tqgnd8zygRx7t33Ybw40o07MrhzNEHgYavUukaPje5by78JIWHgk";
+ sout << "l7nb/TK+9ndVLrAThJ4v+GiPT3kh9H1tAAAAAQhbLa06pQjhrnjTXcRox1ZBEAV9/q1zAA==";
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ // Declare the logger we will use in this test. The name of the tester
+ // should start with "test."
+ logger dlog("test.serialize");
+
+ void serialize_test (
+ )
+ /*!
+ ensures
+ - runs tests on the serialization code for compliance with the specs
+ !*/
+ {
+
+
+ print_spinner();
+
+ ostringstream sout;
+ test_object obj;
+
+ obj.set_state_1();
+ obj.assert_in_state_1();
+ serialize(obj, sout);
+ obj.assert_in_state_1();
+
+ obj.set_state_2();
+ obj.assert_in_state_2();
+ serialize(obj, sout);
+ obj.assert_in_state_2();
+
+
+ istringstream sin(sout.str());
+
+ deserialize(obj,sin);
+ obj.assert_in_state_1();
+ deserialize(obj,sin);
+ obj.assert_in_state_2();
+
+
+ // now do the same thing as above but deserialize from some stored binary
+ // data to make sure the serialized values are portable between different
+ // machines
+
+ sin.clear();
+ sin.str(get_decoded_string());
+ deserialize(obj,sin);
+ obj.assert_in_state_1();
+ deserialize(obj,sin);
+ obj.assert_in_state_2();
+
+
+ sin.clear();
+ sin.str(get_decoded_string2());
+ deserialize(obj,sin);
+ obj.assert_in_state_1();
+ deserialize(obj,sin);
+ obj.assert_in_state_2();
+
+
+ /*
+ // This is the code that produced the encoded data stored in the get_decoded_string() function
+ ofstream fout("stuff.bin",ios::binary);
+ obj.set_state_1();
+ obj.assert_in_state_1();
+ serialize(obj, fout);
+ obj.assert_in_state_1();
+
+ obj.set_state_2();
+ obj.assert_in_state_2();
+ serialize(obj, fout);
+ obj.assert_in_state_2();
+ */
+
+
+ test_object obj2;
+ obj.set_state_1();
+ obj2.set_state_2();
+ dlib::serialize("serialization_test.dat") << obj << obj2;
+ obj.assert_in_state_1();
+ obj2.assert_in_state_2();
+ obj.set_state_2();
+ obj2.set_state_1();
+ obj.assert_in_state_2();
+ obj2.assert_in_state_1();
+ dlib::deserialize("serialization_test.dat") >> obj >> obj2;
+ obj.assert_in_state_1();
+ obj2.assert_in_state_2();
+ }
+
+
+ template <typename T>
+ void test_vector (
+ )
+ {
+ std::vector<T> a, b;
+
+ for (int i = -10; i < 30; ++i)
+ {
+ a.push_back(i);
+ }
+
+ ostringstream sout;
+ dlib::serialize(a, sout);
+ istringstream sin(sout.str());
+
+ dlib::deserialize(b, sin);
+
+
+ DLIB_TEST(a.size() == b.size());
+ DLIB_TEST(a.size() == 40);
+ for (unsigned long i = 0; i < a.size(); ++i)
+ {
+ DLIB_TEST(a[i] == b[i]);
+ }
+
+ std::vector<T> c;
+ sout.str("");
+ dlib::serialize(c, sout);
+ sin.str(sout.str());
+ dlib::deserialize(a, sin);
+ DLIB_TEST(a.size() == 0);
+ DLIB_TEST(c.size() == 0);
+ }
+
+ void test_std_array (
+ )
+ {
+ std::array<int,5> a, b;
+
+ a = {1, 2, 3, 4, 5};
+
+ ostringstream sout;
+ dlib::serialize(a, sout);
+ istringstream sin(sout.str());
+
+ dlib::deserialize(b, sin);
+
+
+ DLIB_TEST(a.size() == b.size());
+ DLIB_TEST(a.size() == 5);
+ for (unsigned long i = 0; i < a.size(); ++i)
+ {
+ DLIB_TEST(a[i] == b[i]);
+ }
+
+ std::array<int,0> aa, bb;
+ sout.str("");
+ dlib::serialize(aa, sout);
+ sin.str(sout.str());
+ dlib::deserialize(bb, sin);
+ DLIB_TEST(bb.size() == 0);
+ }
+
+ void test_vector_bool (
+ )
+ {
+ std::vector<bool> a, b;
+
+ a.push_back(true);
+ a.push_back(true);
+ a.push_back(false);
+ a.push_back(true);
+ a.push_back(false);
+ a.push_back(true);
+
+ ostringstream sout;
+ dlib::serialize(a, sout);
+ istringstream sin(sout.str());
+
+ dlib::deserialize(b, sin);
+
+
+ DLIB_TEST(a.size() == b.size());
+ DLIB_TEST(a.size() == 6);
+ for (unsigned long i = 0; i < a.size(); ++i)
+ {
+ DLIB_TEST(a[i] == b[i]);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ // This function returns the contents of the file 'matarray.dat'
+ const std::string get_decoded_string_matarray_old()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'matarray.dat' we want to decode and return.
+ sout << "AW852sEbTIeV+m/wLUcKJKPW+6IclviUWZcFh1daDZ0blDjPNTgPx0Lv56sIEwlG4I6C5OJzJBkZ";
+ sout << "PvczLjS7IEKh6eg7amNOyEexsQSgojL1oMe2gDEfkyInUGPJV90sNS0cvp/hIB134V8JCTYUP6vH";
+ sout << "9qpegLSIIQG+/NjLWyK2472vC88BJfKgkL3CPLMjQwB3tB928FNLbESDLIvpnb6q9ve68iuoyZZt";
+ sout << "z3TTJxHW3MIdgzuhNomvPxfo/Q+7lC/Orj0FewUX90al6DckwzOtLVRidh/ZKpsQsxzJYQGkjdX5";
+ sout << "mDzzXKqQb3Y3DnzEmwtRD9CUON3iRv1r26gHWLYorrYA";
+
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ // This function returns the contents of the file 'matarray.dat'
+ const std::string get_decoded_string_matarray()
+ {
+ dlib::base64 base64_coder;
+ dlib::compress_stream::kernel_1ea compressor;
+ std::ostringstream sout;
+ std::istringstream sin;
+
+ // The base64 encoded data from the file 'matarray.dat' we want to decode and return.
+ sout << "gO6XH2WGbm8Xaw3a5FJbh3V823W6P2Qk/vHaAAAAARccIppHWdmViaKby7JA5PQvXjYMWUYvXRHv";
+ sout << "xPdURZl1un3CT/rjT11Yry0y3+1W7GBmfBJ0gVFKGdiGuqoNAMtmzL/ll3YfEQ7ED7aB33aDTktw";
+ sout << "AWVkHT+gqTbKwjP+8YvB3s3ziK640ITOAWazAghKDVl7AHGn+fjq29paBZMczuJofl8FinZUhwa9";
+ sout << "Ol5gdAEQa6VZDmJUeo2soTJcEDpkW9LkRmXvjQkyEHfEHQNFDfQq4p2U+dHz4lOKlcj3VzQIeG/s";
+ sout << "oxa9KhJND4aQ5xeNUUHUzFBU3XhQHlyDIn/RNdX/ZwA=";
+
+
+ // Put the data into the istream sin
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decode the base64 text into its compressed binary form
+ base64_coder.decode(sin,sout);
+ sin.clear();
+ sin.str(sout.str());
+ sout.str("");
+
+ // Decompress the data into its original form
+ compressor.decompress(sin,sout);
+
+ // Return the decoded and decompressed data
+ return sout.str();
+ }
+
+ void setup_mats_and_arrays (
+ array2d<int>& a,
+ matrix<int>& m,
+ array2d<unsigned char>& img1,
+ array2d<rgb_pixel>& img2,
+ array2d<bgr_pixel>& img3,
+ array2d<rgb_alpha_pixel>& img4,
+ array2d<hsi_pixel>& img5
+ )
+ {
+ a.set_size(3,5);
+ int cnt = 0;
+ for (long r = 0; r < a.nr(); ++r)
+ {
+ for (long c = 0; c < a.nc(); ++c)
+ {
+ a[r][c] = cnt++;
+ }
+ }
+ m = mat(a);
+
+ img1.set_size(3,5);
+ img2.set_size(3,5);
+ img3.set_size(3,5);
+ img4.set_size(3,5);
+ img5.set_size(3,5);
+
+ assign_all_pixels(img1, 0);
+ assign_all_pixels(img2, 0);
+ assign_all_pixels(img3, 0);
+ assign_all_pixels(img4, 0);
+ assign_all_pixels(img5, 0);
+
+ unsigned char pcnt = 0;
+ for (long r = 0; r < img1.nr(); ++r)
+ {
+ for (long c = 0; c < img1.nc(); ++c)
+ {
+ rgb_alpha_pixel temp;
+ temp.red = pcnt++;
+ temp.green = pcnt++;
+ temp.blue = pcnt++;
+ temp.alpha = 150+pcnt++;
+ assign_pixel(img1[r][c], temp);
+ assign_pixel(img2[r][c], temp);
+ assign_pixel(img3[r][c], temp);
+ assign_pixel(img4[r][c], temp);
+ }
+ }
+
+ for (long r = 0; r < img5.nr(); ++r)
+ {
+ for (long c = 0; c < img5.nc(); ++c)
+ {
+ img5[r][c].h = pcnt++;
+ img5[r][c].s = pcnt++;
+ img5[r][c].i = pcnt++;
+ }
+ }
+ }
+
+
+ void test_deserialize(
+ std::istream& fin
+ )
+ {
+ array2d<int> a;
+ matrix<int> m;
+ array2d<unsigned char> img1;
+ array2d<rgb_pixel> img2;
+ array2d<bgr_pixel> img3;
+ array2d<rgb_alpha_pixel> img4;
+ array2d<hsi_pixel> img5;
+ setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5);
+
+
+ array2d<unsigned char> img1_;
+ array2d<rgb_pixel> img2_;
+ array2d<bgr_pixel> img3_;
+ array2d<rgb_alpha_pixel> img4_;
+ array2d<hsi_pixel> img5_;
+
+ matrix<int> m_;
+ array2d<int> a_;
+
+ deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a));
+ deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m));
+ deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a));
+ deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m));
+
+ deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1));
+ deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2));
+ deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3));
+ deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4));
+ deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5));
+ }
+
+ void test_deserialize_all_array2d(
+ std::istream& fin
+ )
+ {
+ array2d<int> a;
+ matrix<int> m;
+ array2d<unsigned char> img1;
+ array2d<rgb_pixel> img2;
+ array2d<bgr_pixel> img3;
+ array2d<rgb_alpha_pixel> img4;
+ array2d<hsi_pixel> img5;
+ setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5);
+
+
+ array2d<unsigned char> img1_;
+ array2d<rgb_pixel> img2_;
+ array2d<bgr_pixel> img3_;
+ array2d<rgb_alpha_pixel> img4_;
+ array2d<hsi_pixel> img5_;
+
+ array2d<int> m_;
+ array2d<int> a_;
+
+ deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a));
+ deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m));
+ deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a));
+ deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m));
+
+ deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1));
+ deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2));
+ deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3));
+ deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4));
+ deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5));
+ }
+
+ void test_deserialize_all_matrix(
+ std::istream& fin
+ )
+ {
+ array2d<int> a;
+ matrix<int> m;
+ array2d<unsigned char> img1;
+ array2d<rgb_pixel> img2;
+ array2d<bgr_pixel> img3;
+ array2d<rgb_alpha_pixel> img4;
+ array2d<hsi_pixel> img5;
+ setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5);
+
+
+ matrix<unsigned char> img1_;
+ matrix<rgb_pixel> img2_;
+ matrix<bgr_pixel> img3_;
+ matrix<rgb_alpha_pixel> img4_;
+ matrix<hsi_pixel> img5_;
+
+ matrix<int> m_;
+ matrix<int> a_;
+
+ deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a));
+ deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m));
+ deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a));
+ deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m));
+
+ deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1));
+ deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2));
+ deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3));
+ deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4));
+ deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5));
+ }
+
+ void test_array2d_and_matrix_serialization()
+ {
+ ostringstream sout;
+ array2d<int> a;
+ matrix<int> m;
+ array2d<unsigned char> img1;
+ array2d<rgb_pixel> img2;
+ array2d<bgr_pixel> img3;
+ array2d<rgb_alpha_pixel> img4;
+ array2d<hsi_pixel> img5;
+ setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5);
+
+ serialize(a, sout);
+ serialize(m, sout);
+ serialize(a, sout);
+ serialize(m, sout);
+
+ serialize(img1, sout);
+ serialize(img2, sout);
+ serialize(img3, sout);
+ serialize(img4, sout);
+ serialize(img5, sout);
+
+ // --------------------
+
+ {
+ istringstream sin(sout.str());
+ test_deserialize(sin);
+ }
+ {
+ istringstream sin(sout.str());
+ test_deserialize_all_array2d(sin);
+ }
+ {
+ istringstream sin(sout.str());
+ test_deserialize_all_matrix(sin);
+ }
+
+
+ {
+ istringstream sin(get_decoded_string_matarray());
+ test_deserialize(sin);
+ }
+ {
+ istringstream sin(get_decoded_string_matarray());
+ test_deserialize_all_array2d(sin);
+ }
+ {
+ istringstream sin(get_decoded_string_matarray());
+ test_deserialize_all_matrix(sin);
+ }
+
+
+ {
+ // Make sure we can still deserialize the serialization
+ // format for array2d and matrix objects used by older versions
+ // of dlib.
+ istringstream sin(get_decoded_string_matarray_old());
+ test_deserialize(sin);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_strings()
+ {
+ string str1 = "stuff";
+ char buf[6];
+ buf[0] = 0;
+ buf[1] = 1;
+ buf[2] = 2;
+ buf[3] = 0;
+ buf[4] = 3;
+ buf[5] = 3;
+
+ dlib::serialize("ser_test_string.dat") << str1 << buf << "morestuff" << "";
+
+ string str2, str3, str4;
+ char buf2[6];
+ memset(buf2,0,sizeof(buf2));
+ dlib::deserialize("ser_test_string.dat") >> str2 >> buf2 >> str3 >> str4;
+ DLIB_TEST(str2 == "stuff");
+ DLIB_TEST(str3 == "morestuff");
+ DLIB_TEST(str4 == "");
+ DLIB_TEST(buf2[0] == 0);
+ DLIB_TEST(buf2[1] == 1);
+ DLIB_TEST(buf2[2] == 2);
+ DLIB_TEST(buf2[3] == 0);
+ DLIB_TEST(buf2[4] == 3);
+ DLIB_TEST(buf2[5] == 3);
+
+
+ ofstream fout("ser_test_string.dat", ios::binary);
+ dlib::serialize(str1, fout);
+ dlib::serialize(buf, fout);
+ dlib::serialize("morestuff", fout);
+ fout.close();
+ ifstream fin("ser_test_string.dat", ios::binary);
+ memset(buf2,0,sizeof(buf2));
+ str2.clear();
+ str3.clear();
+ dlib::deserialize(str2, fin);
+ dlib::deserialize(buf2, fin);
+ dlib::deserialize(str3, fin);
+
+ DLIB_TEST(str2 == "stuff");
+ DLIB_TEST(str3 == "morestuff");
+ DLIB_TEST(buf2[0] == 0);
+ DLIB_TEST(buf2[1] == 1);
+ DLIB_TEST(buf2[2] == 2);
+ DLIB_TEST(buf2[3] == 0);
+ DLIB_TEST(buf2[4] == 3);
+ DLIB_TEST(buf2[5] == 3);
+
+
+
+ // make sure ramdump() overloads compile and work.
+ {
+ matrix<double,2,2> a = {1,2,3,4};
+ const matrix<double,2,2> b = {3,2,3,4};
+ dlib::serialize("ramdump_mat.dat") << ramdump(a) << ramdump(b);
+ matrix<double,2,2> A, B;
+ dlib::deserialize("ramdump_mat.dat") >> ramdump(A) >> ramdump(B);
+
+ DLIB_TEST(A == a);
+ DLIB_TEST(B == b);
+ A = 0;
+ B = 0;
+ DLIB_TEST(A != a);
+ DLIB_TEST(B != b);
+
+ ostringstream sout;
+ dlib::serialize(ramdump(a), sout);
+ dlib::serialize(ramdump(b), sout);
+ istringstream sin(sout.str());
+ dlib::deserialize(ramdump(A), sin);
+ dlib::deserialize(ramdump(B), sin);
+
+ DLIB_TEST(A == a);
+ DLIB_TEST(B == b);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class serialize_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a test for the serialization . When it is constructed
+ it adds itself into the testing framework. The command line switch is
+ specified as test_serialize by passing that string to the tester constructor.
+ !*/
+ public:
+ serialize_tester (
+ ) :
+ tester ("test_serialize",
+ "Runs tests on the serialization code.")
+ {}
+
+ void perform_test (
+ )
+ {
+ serialize_test();
+ test_vector<char>();
+ test_vector<unsigned char>();
+ test_vector<int>();
+ test_vector_bool();
+ test_array2d_and_matrix_serialization();
+ test_strings();
+ test_std_array();
+ }
+ } a;
+
+
+}
+
+
diff --git a/ml/dlib/dlib/test/set.cpp b/ml/dlib/dlib/test/set.cpp
new file mode 100644
index 000000000..f8d3bd374
--- /dev/null
+++ b/ml/dlib/dlib/test/set.cpp
@@ -0,0 +1,464 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/set.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.set");
+
+ template <
+ typename set
+ >
+ void set_compare_test (
+ )
+ /*!
+ requires
+ - set is an implementation of set/set_compare_abstract.h and
+ is instantiated with int
+ ensures
+ - runs tests on set for compliance with the specs
+ !*/
+ {
+
+
+ srand(static_cast<unsigned int>(time(0)));
+
+
+
+ set test, test2;
+
+ enumerable<const int>& e = test;
+ DLIB_TEST(e.at_start() == true);
+
+ for (int j = 0; j < 4; ++j)
+ {
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+
+
+ int a,b = 0;
+ a = 8;
+ test.add(a);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(test.is_member(8) == true);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+ a = 53;
+ test.add(a);
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test.is_member(53) == true);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+
+
+ swap(test,test2);
+
+
+
+ DLIB_TEST(test2.is_member(8) == true);
+ DLIB_TEST(test2.is_member(5) == false);
+ DLIB_TEST(test2.is_member(0) == false);
+ DLIB_TEST(test2.is_member(-999) == false);
+ DLIB_TEST(test2.is_member(4999) == false);
+ DLIB_TEST(test2.size() == 2);
+ DLIB_TEST(test2.is_member(53) == true);
+ DLIB_TEST(test2.is_member(5) == false);
+ DLIB_TEST(test2.is_member(0) == false);
+ DLIB_TEST(test2.is_member(-999) == false);
+ DLIB_TEST(test2.is_member(4999) == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_member(8) == false);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.is_member(53) == false);
+ DLIB_TEST(test.is_member(5) == false);
+ DLIB_TEST(test.is_member(0) == false);
+ DLIB_TEST(test.is_member(-999) == false);
+ DLIB_TEST(test.is_member(4999) == false);
+
+
+ test.clear();
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+ test.clear();
+ DLIB_TEST(test.size() == 0);
+
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ DLIB_TEST(test.size() == 10000);
+
+ int count = 0;
+ a = 0;
+ while (test.move_next())
+ {
+ enumerable<const int>& gogo = test;
+ gogo.element();
+
+ DLIB_TEST(test.element() == test.element());
+ DLIB_TEST(test.element() == test.element());
+ DLIB_TEST(test.element() == test.element());
+
+ DLIB_TEST(a <= test.element());
+ a = test.element();
+ ++count;
+ }
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.move_next() == false);
+
+ DLIB_TEST(count == 10000);
+
+ test.swap(test2);
+
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test2.size() == 10000);
+ count = 0;
+ a = -1;
+ test2.reset();
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(a < test2.element());
+ a = test2.element();
+ ++count;
+ }
+ DLIB_TEST(test2.size() == 10000);
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.move_next() == false);
+
+
+
+ test2.clear();
+ DLIB_TEST(test2.size() == 0);
+ DLIB_TEST(test2.at_start() == true);
+
+ while (test.size() < 20000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ DLIB_TEST(test.at_start() == true);
+
+ {
+ int* array = new int[test.size()];
+ int* tmp = array;
+
+ count = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element() == test.element());
+ DLIB_TEST(test.element() == test.element());
+ DLIB_TEST(test.element() == test.element());
+ *tmp = test.element();
+ ++tmp;
+ ++count;
+ }
+ DLIB_TEST(count == 20000);
+
+ // serialize the state of test, then clear test, then
+ // load the state back into test.
+ ostringstream sout;
+ serialize(test,sout);
+ DLIB_TEST(test.at_start() == true);
+ istringstream sin(sout.str());
+ test.clear();
+ deserialize(test,sin);
+
+
+
+ tmp = array;
+ for (int i = 0; i < 20000; ++i)
+ {
+ DLIB_TEST(test.is_member(*tmp) == true);
+ ++tmp;
+ }
+
+ DLIB_TEST(test.size() == 20000);
+
+ tmp = array;
+ count = 0;
+ while (test.size() > 10000)
+ {
+ test.remove(*tmp,a);
+ DLIB_TEST(*tmp == a);
+ ++tmp;
+ ++count;
+ }
+ DLIB_TEST(count == 10000);
+ DLIB_TEST(test.size() == 10000);
+
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element() == *tmp);
+ DLIB_TEST(test.element() == *tmp);
+ DLIB_TEST(test.element() == *tmp);
+ ++tmp;
+ ++count;
+ }
+ DLIB_TEST(count == 20000);
+ DLIB_TEST(test.size() == 10000);
+
+ while (test.size() < 20000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ test2.swap(test);
+
+ count = 0;
+ a = 0;
+ while (test2.move_next())
+ {
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(test2.element() == test2.element());
+ DLIB_TEST(a <= test2.element());
+ a = test2.element();
+ ++count;
+ }
+
+ DLIB_TEST(count == 20000);
+ DLIB_TEST(test2.size() == 20000);
+
+ a = -1;
+ while (test2.size()>0)
+ {
+ test2.remove_any(b);
+ DLIB_TEST( a < b);
+ a = b;
+ }
+
+ DLIB_TEST(test2.size() == 0);
+ delete [] array;
+ }
+
+ test.clear();
+ test2.clear();
+ while (test.size() < 10000)
+ {
+ a = ::rand();
+ if (!test.is_member(a))
+ test.add(a);
+ }
+
+ count = 0;
+ a = -1;
+ while (test.move_next())
+ {
+ DLIB_TEST(a < test.element());
+ a = test.element();
+ ++count;
+ if (count == 5000)
+ break;
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ test.reset();
+
+ count = 0;
+ a = -1;
+ while (test.move_next())
+ {
+ DLIB_TEST(a < test.element());
+ a = test.element();
+ ++count;
+ DLIB_TEST(test.current_element_valid() == true);
+ }
+
+ DLIB_TEST(count == 10000);
+
+
+ test.clear();
+ test2.clear();
+ }
+
+
+
+ {
+ DLIB_TEST(test == test2);
+ DLIB_TEST((test < test2) == false);
+ DLIB_TEST((test2 < test) == false);
+
+ int a = 3, b = 3;
+ test.add(a);
+ test2.add(b);
+ test.move_next();
+ DLIB_TEST(test == test2);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test.move_next();
+ DLIB_TEST((test < test2) == false);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test.move_next();
+ DLIB_TEST((test2 < test) == false);
+ DLIB_TEST(test.at_start() && test2.at_start());
+
+ a = 2; b = 5;
+ test.add(a);
+ test2.add(b);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test == test2) == false);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test < test2) == true);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test2 < test) == false);
+ DLIB_TEST(test.at_start() && test2.at_start());
+
+
+ a = 8;
+ test.add(a);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test == test2) == false);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test < test2) == false);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test2 < test) == true);
+ DLIB_TEST(test.at_start() && test2.at_start());
+
+ test.clear();
+
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test == test2) == false);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test < test2) == true);
+ DLIB_TEST(test.at_start() && test2.at_start());
+ test2.move_next();
+ DLIB_TEST((test2 < test) == false);
+ DLIB_TEST(test.at_start() && test2.at_start());
+
+
+ }
+
+
+ {
+ test.clear();
+ DLIB_TEST(test.size() == 0);
+ int a = 5;
+ test.add(a);
+ a = 7;
+ test.add(a);
+ DLIB_TEST(test.size() == 2);
+ DLIB_TEST(test.is_member(7));
+ DLIB_TEST(test.is_member(5));
+ test.destroy(7);
+ DLIB_TEST(test.size() == 1);
+ DLIB_TEST(!test.is_member(7));
+ DLIB_TEST(test.is_member(5));
+ test.destroy(5);
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(!test.is_member(7));
+ DLIB_TEST(!test.is_member(5));
+ }
+
+
+ }
+
+
+
+
+ class set_tester : public tester
+ {
+ public:
+ set_tester (
+ ) :
+ tester ("test_set",
+ "Runs tests on the set component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing compare_1a";
+ set_compare_test<dlib::set<int>::compare_1a> ();
+ dlog << LINFO << "testing compare_1a_c";
+ set_compare_test<dlib::set<int>::compare_1a_c>();
+ dlog << LINFO << "testing compare_1b";
+ set_compare_test<dlib::set<int>::compare_1b> ();
+ dlog << LINFO << "testing compare_1b_c";
+ set_compare_test<dlib::set<int>::compare_1b_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/sldf.cpp b/ml/dlib/dlib/test/sldf.cpp
new file mode 100644
index 000000000..4ca9a3dd0
--- /dev/null
+++ b/ml/dlib/dlib/test/sldf.cpp
@@ -0,0 +1,296 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm.h>
+#include <dlib/rand.h>
+#include <dlib/string.h>
+#include <vector>
+#include <sstream>
+#include <ctime>
+#include <dlib/data_io.h>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.sldf");
+
+
+ class sldf_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ sldf_tester (
+ ) :
+ tester (
+ "test_sldf", // the command line argument name for this test
+ "Run tests on the simplify_linear_decision_function routines.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+ dlib::rand rnd;
+
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ typedef std::map<unsigned long,double> sample_type;
+
+ typedef matrix<double,0,1> dense_sample_type;
+
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+ typedef linear_kernel<dense_sample_type> dense_kernel_type;
+
+
+ svm_nu_trainer<kernel_type> linear_trainer;
+ linear_trainer.set_nu(0.2);
+ svm_nu_trainer<dense_kernel_type> dense_linear_trainer;
+ dense_linear_trainer.set_nu(0.2);
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ // make an instance of a sample vector so we can use it below
+ sample_type sample;
+
+ // Now lets go into a loop and randomly generate 300 samples.
+ double label = +1;
+ for (int i = 0; i < 300; ++i)
+ {
+ // flip this flag
+ label *= -1;
+
+ sample.clear();
+
+ // now make a random sparse sample with at most 10 non-zero elements
+ for (int j = 0; j < 10; ++j)
+ {
+ int idx = rnd.get_random_32bit_number()%100;
+ double value = rnd.get_random_double();
+
+ sample[idx] = label*value;
+ }
+
+ // Also save the samples we are generating so we can let the svm_c_linear_trainer
+ // learn from them below.
+ samples.push_back(sample);
+ labels.push_back(label);
+ }
+
+
+ {
+ print_spinner();
+ dlog << LINFO << " test with sparse samples ";
+ decision_function<kernel_type> df = linear_trainer.train(samples, labels);
+
+ dlog << LINFO << "df.basis_vectors.size(): "<< df.basis_vectors.size();
+ DLIB_TEST(df.basis_vectors.size() > 4);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(df, samples, labels);
+
+ // save the outputs of the decision function before we mess with it
+ std::vector<double> prev_vals;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ prev_vals.push_back(df(samples[i]));
+
+ df = simplify_linear_decision_function(df);
+
+ dlog << LINFO << "df.basis_vectors.size(): "<< df.basis_vectors.size();
+ DLIB_TEST(df.basis_vectors.size() == 1);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(df, samples, labels);
+
+ // now check that the simplified decision function still produces the same results
+ std::vector<double> cur_vals;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ cur_vals.push_back(df(samples[i]));
+
+ const double err = max(abs(mat(cur_vals) - mat(prev_vals)));
+ dlog << LINFO << "simplify error: "<< err;
+ DLIB_TEST(err < 1e-13);
+
+ }
+
+
+ // same as above but call simplify_linear_decision_function() two times
+ {
+ print_spinner();
+ dlog << LINFO << " test with sparse samples ";
+ decision_function<kernel_type> df = linear_trainer.train(samples, labels);
+
+ dlog << LINFO << "df.basis_vectors.size(): "<< df.basis_vectors.size();
+ DLIB_TEST(df.basis_vectors.size() > 4);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(df, samples, labels);
+
+ // save the outputs of the decision function before we mess with it
+ std::vector<double> prev_vals;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ prev_vals.push_back(df(samples[i]));
+
+ df = simplify_linear_decision_function(df);
+ df = simplify_linear_decision_function(df);
+
+ dlog << LINFO << "df.basis_vectors.size(): "<< df.basis_vectors.size();
+ DLIB_TEST(df.basis_vectors.size() == 1);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(df, samples, labels);
+
+ // now check that the simplified decision function still produces the same results
+ std::vector<double> cur_vals;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ cur_vals.push_back(df(samples[i]));
+
+ const double err = max(abs(mat(cur_vals) - mat(prev_vals)));
+ dlog << LINFO << "simplify error: "<< err;
+ DLIB_TEST(err < 1e-13);
+
+ }
+
+
+ {
+ print_spinner();
+ dlog << LINFO << " test with dense samples ";
+ std::vector<dense_sample_type> dense_samples(sparse_to_dense(samples));
+
+ // In addition to the rule we learned with the pegasos trainer lets also use our linear_trainer
+ // to learn a decision rule.
+ decision_function<dense_kernel_type> dense_df = dense_linear_trainer.train(dense_samples, labels);
+
+ dlog << LINFO << "dense_df.basis_vectors.size(): "<< dense_df.basis_vectors.size();
+ DLIB_TEST(dense_df.basis_vectors.size() > 4);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels);
+
+ // save the outputs of the decision function before we mess with it
+ std::vector<double> prev_vals;
+ for (unsigned long i = 0; i < dense_samples.size(); ++i)
+ prev_vals.push_back(dense_df(dense_samples[i]));
+
+ dense_df = simplify_linear_decision_function(dense_df);
+
+ dlog << LINFO << "dense_df.basis_vectors.size(): "<< dense_df.basis_vectors.size();
+ DLIB_TEST(dense_df.basis_vectors.size() == 1);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels);
+
+
+ // now check that the simplified decision function still produces the same results
+ std::vector<double> cur_vals;
+ for (unsigned long i = 0; i < dense_samples.size(); ++i)
+ cur_vals.push_back(dense_df(dense_samples[i]));
+
+ const double err = max(abs(mat(cur_vals) - mat(prev_vals)));
+ dlog << LINFO << "simplify error: "<< err;
+ DLIB_TEST(err < 1e-13);
+ }
+
+ // same as above but call simplify_linear_decision_function() two times
+ {
+ print_spinner();
+ dlog << LINFO << " test with dense samples ";
+ std::vector<dense_sample_type> dense_samples(sparse_to_dense(samples));
+
+ // In addition to the rule we learned with the pegasos trainer lets also use our linear_trainer
+ // to learn a decision rule.
+ decision_function<dense_kernel_type> dense_df = dense_linear_trainer.train(dense_samples, labels);
+
+ dlog << LINFO << "dense_df.basis_vectors.size(): "<< dense_df.basis_vectors.size();
+ DLIB_TEST(dense_df.basis_vectors.size() > 4);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels);
+
+ // save the outputs of the decision function before we mess with it
+ std::vector<double> prev_vals;
+ for (unsigned long i = 0; i < dense_samples.size(); ++i)
+ prev_vals.push_back(dense_df(dense_samples[i]));
+
+ dense_df = simplify_linear_decision_function(dense_df);
+ dense_df = simplify_linear_decision_function(dense_df);
+
+ dlog << LINFO << "dense_df.basis_vectors.size(): "<< dense_df.basis_vectors.size();
+ DLIB_TEST(dense_df.basis_vectors.size() == 1);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels);
+
+
+ // now check that the simplified decision function still produces the same results
+ std::vector<double> cur_vals;
+ for (unsigned long i = 0; i < dense_samples.size(); ++i)
+ cur_vals.push_back(dense_df(dense_samples[i]));
+
+ const double err = max(abs(mat(cur_vals) - mat(prev_vals)));
+ dlog << LINFO << "simplify error: "<< err;
+ DLIB_TEST(err < 1e-13);
+ }
+
+ {
+ print_spinner();
+
+ dlog << LINFO << " test with sparse samples and a vector normalizer";
+ std::vector<dense_sample_type> dense_samples(sparse_to_dense(samples));
+ std::vector<dense_sample_type> norm_samples;
+
+ // make a normalizer and normalize everything
+ vector_normalizer<dense_sample_type> normalizer;
+ normalizer.train(dense_samples);
+ for (unsigned long i = 0; i < dense_samples.size(); ++i)
+ norm_samples.push_back(normalizer(dense_samples[i]));
+
+ normalized_function<decision_function<dense_kernel_type> > dense_df;
+
+ dense_df.normalizer = normalizer;
+ dense_df.function = dense_linear_trainer.train(norm_samples, labels);
+
+ dlog << LINFO << "dense_df.function.basis_vectors.size(): "<< dense_df.function.basis_vectors.size();
+ DLIB_TEST(dense_df.function.basis_vectors.size() > 4);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels);
+
+ // save the outputs of the decision function before we mess with it
+ std::vector<double> prev_vals;
+ for (unsigned long i = 0; i < dense_samples.size(); ++i)
+ prev_vals.push_back(dense_df(dense_samples[i]));
+
+
+ decision_function<dense_kernel_type> simple_df = simplify_linear_decision_function(dense_df);
+
+ dlog << LINFO << "simple_df.basis_vectors.size(): "<< simple_df.basis_vectors.size();
+ DLIB_TEST(simple_df.basis_vectors.size() == 1);
+
+ dlog << LINFO << "test scores: "<< test_binary_decision_function(simple_df, dense_samples, labels);
+
+
+ // now check that the simplified decision function still produces the same results
+ std::vector<double> cur_vals;
+ for (unsigned long i = 0; i < dense_samples.size(); ++i)
+ cur_vals.push_back(simple_df(dense_samples[i]));
+
+ const double err = max(abs(mat(cur_vals) - mat(prev_vals)));
+ dlog << LINFO << "simplify error: "<< err;
+ DLIB_TEST(err < 1e-13);
+
+ }
+
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ sldf_tester a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/sliding_buffer.cpp b/ml/dlib/dlib/test/sliding_buffer.cpp
new file mode 100644
index 000000000..449ea858e
--- /dev/null
+++ b/ml/dlib/dlib/test/sliding_buffer.cpp
@@ -0,0 +1,439 @@
+// Copyright (C) 2004 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <cstdlib>
+
+#include <dlib/sliding_buffer.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.sliding_buffer");
+
+ template <
+ typename buf
+ >
+ void sliding_buffer_kernel_test (
+ )
+ /*!
+ requires
+ - buf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h
+ - buf is instantiated with T=unsigned char
+ ensures
+ - runs tests on buf for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ buf test;
+
+ DLIB_TEST(test.size() == 0);
+
+ test.set_size(3);
+ buf test2;
+
+ DLIB_TEST(test.size() == 8);
+
+ for (int g = 0; g < 2; ++g)
+ {
+
+ test.clear();
+
+ DLIB_TEST(test.size() == 0);
+ test.set_size(2);
+
+ DLIB_TEST(test.size() == 4);
+
+
+
+ test[0] = 'a';
+ test[1] = 's';
+ test[2] = 'd';
+ test[3] = 'f';
+
+ unsigned long id = test.get_element_id(2);
+ DLIB_TEST(test[test.get_element_index(id)] == 'd');
+
+
+ DLIB_TEST(test[0] == 'a');
+ DLIB_TEST(test[1] == 's');
+ DLIB_TEST(test[2] == 'd');
+ DLIB_TEST(test[3] == 'f');
+
+ DLIB_TEST(test2.size() == 0);
+ swap(test,test2);
+ DLIB_TEST(test2.size() == 4);
+
+ DLIB_TEST(test2[0] == 'a');
+ DLIB_TEST(test2[1] == 's');
+ DLIB_TEST(test2[2] == 'd');
+ DLIB_TEST(test2[3] == 'f');
+
+ swap(test,test2);
+
+ test.rotate_left(4);
+
+
+ DLIB_TEST(test[test.get_element_index(id)] == 'd');
+
+ DLIB_TEST(test[0] == 'a');
+ DLIB_TEST(test[1] == 's');
+ DLIB_TEST(test[2] == 'd');
+ DLIB_TEST(test[3] == 'f');
+
+ test.rotate_right(1);
+
+ DLIB_TEST(test[test.get_element_index(id)] == 'd');
+
+ DLIB_TEST(test[0] == 's');
+ DLIB_TEST(test[1] == 'd');
+ DLIB_TEST(test[2] == 'f');
+ DLIB_TEST(test[3] == 'a');
+
+
+ test.rotate_left(1);
+
+ DLIB_TEST(test[test.get_element_index(id)] == 'd');
+ DLIB_TEST(test[0] == 'a');
+ DLIB_TEST(test[1] == 's');
+ DLIB_TEST(test[2] == 'd');
+ DLIB_TEST(test[3] == 'f');
+
+
+ test.rotate_left(16);
+
+ DLIB_TEST(test[test.get_element_index(id)] == 'd');
+ DLIB_TEST(test[0] == 'a');
+ DLIB_TEST(test[1] == 's');
+ DLIB_TEST(test[2] == 'd');
+ DLIB_TEST(test[3] == 'f');
+
+
+ test.rotate_left(2);
+
+ DLIB_TEST(test[test.get_element_index(id)] == 'd');
+
+ DLIB_TEST(test[0] == 'd');
+ DLIB_TEST(test[1] == 'f');
+ DLIB_TEST(test[2] == 'a');
+ DLIB_TEST(test[3] == 's');
+
+ test.rotate_left(1);
+
+ DLIB_TEST(test[test.get_element_index(id)] == 'd');
+ DLIB_TEST(test[0] == 's');
+ DLIB_TEST(test[1] == 'd');
+ DLIB_TEST(test[2] == 'f');
+ DLIB_TEST(test[3] == 'a');
+
+ test.rotate_left(1);
+
+ DLIB_TEST(test[test.get_element_index(id)] == 'd');
+ DLIB_TEST(test[0] == 'a');
+ DLIB_TEST(test[1] == 's');
+ DLIB_TEST(test[2] == 'd');
+ DLIB_TEST(test[3] == 'f');
+
+ DLIB_TEST(test.size() == 4);
+
+ test[0] = 'x';
+
+ DLIB_TEST(test[0] == 'x');
+ DLIB_TEST(test[1] == 's');
+ DLIB_TEST(test[2] == 'd');
+ DLIB_TEST(test[3] == 'f');
+
+ test.rotate_left(1);
+
+ DLIB_TEST_MSG(test[0] == 'f',test[0]);
+ DLIB_TEST(test[1] == 'x');
+ DLIB_TEST(test[2] == 's');
+ DLIB_TEST(test[3] == 'd');
+
+
+ test[0] = 'x';
+
+ DLIB_TEST(test[0] == 'x');
+ DLIB_TEST(test[1] == 'x');
+ DLIB_TEST(test[2] == 's');
+ DLIB_TEST(test[3] == 'd');
+
+
+ test.rotate_left(1);
+
+
+ DLIB_TEST(test[0] == 'd');
+ DLIB_TEST(test[1] == 'x');
+ DLIB_TEST(test[2] == 'x');
+ DLIB_TEST(test[3] == 's');
+
+
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+
+ test.clear();
+ test2.clear();
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+
+ swap(test,test2);
+
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+ DLIB_TEST(test2.move_next() == false);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test2.current_element_valid() == false);
+
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.at_start() == false);
+
+ test.set_size(3);
+ DLIB_TEST(test.size() == 8);
+
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+ test.reset();
+ DLIB_TEST(test.size() == 8);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+
+
+ test.rotate_right(1);
+ DLIB_TEST(test.size() == 8);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+
+ test.rotate_left(1);
+ DLIB_TEST(test.size() == 8);
+ DLIB_TEST(test.at_start() == true);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == true);
+ DLIB_TEST(test.at_start() == false);
+ DLIB_TEST(test.current_element_valid() == true);
+ test.reset();
+
+
+ for (unsigned long i = 0; i < test.size(); ++i)
+ {
+ test[i] = static_cast<unsigned char>(i);
+ }
+
+ unsigned long count = 0;
+ while (test.move_next())
+ {
+ DLIB_TEST(test.element() == count);
+ ++count;
+ }
+
+ DLIB_TEST(count == test.size());
+
+
+ test2.clear();
+ ostringstream sout;
+ istringstream sin;
+
+ serialize(test,sout);
+ sin.str(sout.str());
+ deserialize(test2,sin);
+
+ char ch;
+ sin >> ch;
+ DLIB_TEST( !sin);
+
+ DLIB_TEST(test2.size() == test.size());
+
+
+ for (unsigned long i = 0; i < test.size(); ++i)
+ {
+ DLIB_TEST_MSG(test[i] == test2[i],
+ "\ni: " << i <<
+ "\ntest[i]: " << test[i] <<
+ "\ntest2[i]: " << test2[i]);
+ }
+
+ count = 0;
+ while (test.move_next() && test2.move_next())
+ {
+ DLIB_TEST(test.element() == count);
+ DLIB_TEST(test2.element() == count);
+ ++count;
+ }
+
+ DLIB_TEST(test2.size() == count);
+ DLIB_TEST(test.size() == count);
+
+ test2.clear();
+
+
+ } // for (int g = 0; g < 2; ++g)
+
+
+ }
+
+
+
+ void test_circular_buffer()
+ {
+ circular_buffer<int> buf;
+
+ DLIB_TEST(buf.size() == 0);
+
+ buf.assign(4, 0);
+ DLIB_TEST(buf.size() == 4);
+
+ DLIB_TEST(buf[0] == 0);
+ DLIB_TEST(buf[1] == 0);
+ DLIB_TEST(buf[2] == 0);
+ DLIB_TEST(buf[3] == 0);
+ buf.push_back(1);
+ DLIB_TEST(buf[0] == 0);
+ DLIB_TEST(buf[1] == 0);
+ DLIB_TEST(buf[2] == 0);
+ DLIB_TEST(buf[3] == 1);
+ buf.push_back(2);
+ DLIB_TEST(buf[0] == 0);
+ DLIB_TEST(buf[1] == 0);
+ DLIB_TEST(buf[2] == 1);
+ DLIB_TEST(buf[3] == 2);
+ buf.push_front(3);
+ DLIB_TEST(buf[0] == 3);
+ DLIB_TEST(buf[1] == 0);
+ DLIB_TEST(buf[2] == 0);
+ DLIB_TEST(buf[3] == 1);
+ buf.push_front(4);
+ DLIB_TEST(buf.front() == 4);
+ DLIB_TEST(buf[0] == 4);
+ DLIB_TEST(buf[1] == 3);
+ DLIB_TEST(buf[2] == 0);
+ DLIB_TEST(buf[3] == 0);
+
+ buf.assign(4, 5);
+ DLIB_TEST(buf[0] == 5);
+ DLIB_TEST(buf[1] == 5);
+ DLIB_TEST(buf[2] == 5);
+ DLIB_TEST(buf[3] == 5);
+
+ buf.push_back(3);
+ DLIB_TEST(buf[0] == 5);
+ DLIB_TEST(buf[1] == 5);
+ DLIB_TEST(buf[2] == 5);
+ DLIB_TEST(buf[3] == 3);
+ buf.push_back(2);
+ DLIB_TEST(buf[0] == 5);
+ DLIB_TEST(buf[1] == 5);
+ DLIB_TEST(buf[2] == 3);
+ DLIB_TEST(buf[3] == 2);
+ buf.push_back(1);
+ DLIB_TEST(buf[0] == 5);
+ DLIB_TEST(buf[1] == 3);
+ DLIB_TEST(buf[2] == 2);
+ DLIB_TEST(buf[3] == 1);
+ buf.push_back(0);
+ DLIB_TEST(buf[0] == 3);
+ DLIB_TEST(buf[1] == 2);
+ DLIB_TEST(buf[2] == 1);
+ DLIB_TEST(buf[3] == 0);
+ buf.push_back(-1);
+ DLIB_TEST(buf.back() == -1);
+ DLIB_TEST(buf[0] == 2);
+ DLIB_TEST(buf[1] == 1);
+ DLIB_TEST(buf[2] == 0);
+ DLIB_TEST(buf[3] == -1);
+
+ buf.resize(1);
+ buf[0] = 9;
+ DLIB_TEST(buf.size() == 1);
+ DLIB_TEST(buf[0] == 9);
+ buf.push_back(1);
+ DLIB_TEST(buf[0] == 1);
+ buf.push_back(4);
+ DLIB_TEST(buf[0] == 4);
+ buf.push_front(3);
+ DLIB_TEST(buf[0] == 3);
+
+ buf.clear();
+ DLIB_TEST(buf.size() == 0);
+
+ buf.assign(3, 0);
+
+ circular_buffer<int> buf2, buf3;
+
+ buf.push_back(1);
+ buf.push_back(2);
+
+ ostringstream sout;
+ serialize(buf, sout);
+ istringstream sin(sout.str());
+ deserialize(buf2, sin);
+
+ DLIB_TEST(buf.size() == buf2.size());
+ for (unsigned long i = 0; i < buf.size(); ++i)
+ DLIB_TEST(buf[i] == buf2[i]);
+
+ buf.swap(buf3);
+ DLIB_TEST(buf.size() == 0);
+ DLIB_TEST(buf3.size() == buf2.size());
+ for (unsigned long i = 0; i < buf3.size(); ++i)
+ DLIB_TEST(buf3[i] == buf2[i]);
+
+
+
+ }
+
+
+
+ class sliding_buffer_tester : public tester
+ {
+ public:
+ sliding_buffer_tester (
+ ) :
+ tester ("test_sliding_buffer",
+ "Runs tests on the sliding_buffer component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ sliding_buffer_kernel_test<sliding_buffer<unsigned char>::kernel_1a> ();
+ dlog << LINFO << "testing kernel_1a_c";
+ sliding_buffer_kernel_test<sliding_buffer<unsigned char>::kernel_1a_c>();
+
+ test_circular_buffer();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/smart_pointers.cpp b/ml/dlib/dlib/test/smart_pointers.cpp
new file mode 100644
index 000000000..c2281efda
--- /dev/null
+++ b/ml/dlib/dlib/test/smart_pointers.cpp
@@ -0,0 +1,449 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+// This is a legacy test for old dlib smart pointers which is excluded
+// from CMakeLists.txt. Including this test will pull legacy smart_pointers.h
+// code which is uncompilable on C++17 compilers
+
+#include <dlib/smart_pointers.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include "tester.h"
+
+// Don't warn about auto_ptr
+#if (defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4))) || \
+ (defined(__clang__) && ((__clang_major__ >= 3 && __clang_minor__ >= 4)))
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+namespace
+{
+ bool used_array_delete;
+ template <typename T>
+ struct test_deleter
+ {
+ void operator() (T* item) const
+ {
+ used_array_delete = false;
+ delete item;
+ }
+ };
+
+ template <typename T>
+ struct test_deleter<T[]>
+ {
+ void operator() (T* item) const
+ {
+ used_array_delete = true;
+ delete [] item;
+ }
+ };
+
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.smart_pointers");
+
+ int counter = 0;
+ struct base
+ {
+ int num;
+ virtual ~base() {}
+ };
+
+ struct derived : public base
+ {
+ derived() { ++counter; }
+ ~derived() { --counter; }
+ };
+
+ int deleter_called = 0;
+ void deleter ( derived* p) { ++deleter_called; delete p; }
+ void deleter_base ( base* p) { ++deleter_called; delete p; }
+ typedef void (*D)(derived*);
+ typedef void (*Db)(base*);
+
+ void smart_pointers_test (
+ )
+ /*!
+ ensures
+ - runs tests on the smart pointers for compliance with the specs
+ !*/
+ {
+ counter = 0;
+ deleter_called = 0;
+
+ {
+ DLIB_TEST_MSG(counter == 0,counter);
+ scoped_ptr<base> p1(new derived);
+ scoped_ptr<derived> p2(new derived);
+ scoped_ptr<derived> p3;
+ DLIB_TEST_MSG(counter == 2,counter);
+ DLIB_TEST(!p3);
+
+ p1->num = 1;
+ p2->num = 2;
+ DLIB_TEST(p1->num == 1);
+ DLIB_TEST(p2->num == 2);
+
+ (*p1).num = 3;
+ (*p2).num = 4;
+ DLIB_TEST(p1->num == 3);
+ DLIB_TEST(p2->num == 4);
+
+ DLIB_TEST_MSG(counter == 2,counter);
+
+ DLIB_TEST(p1);
+ DLIB_TEST(p2);
+
+ DLIB_TEST_MSG(counter == 2,counter);
+ p1.reset();
+ DLIB_TEST_MSG(counter == 1,counter);
+ DLIB_TEST(!p1);
+ DLIB_TEST(p2);
+ p1.reset(new derived);
+ DLIB_TEST_MSG(counter == 2,counter);
+ DLIB_TEST(p1);
+
+
+ DLIB_TEST_MSG(counter == 2,counter);
+ p2.reset();
+ DLIB_TEST_MSG(counter == 1,counter);
+ DLIB_TEST(!p2);
+ derived* d = new derived;
+ p2.reset(d);
+ DLIB_TEST(p2.get() == d);
+ DLIB_TEST_MSG(counter == 2,counter);
+ DLIB_TEST(p2);
+ DLIB_TEST(!p3);
+ p2->num = 9;
+ swap(p2,p3);
+ DLIB_TEST(!p2);
+ DLIB_TEST(p3);
+ DLIB_TEST(p3->num == 9);
+ p2.swap(p3);
+ DLIB_TEST(p2);
+ DLIB_TEST(!p3);
+ DLIB_TEST(p2->num == 9);
+
+
+ DLIB_TEST_MSG(counter == 2,counter);
+
+ }
+ DLIB_TEST_MSG(counter == 0,counter);
+
+ {
+ base* realp1 = new derived;
+ derived* realp2 = new derived;
+ dlib::shared_ptr<base> p1(realp1);
+ dlib::shared_ptr<derived> p2(realp2,&deleter);
+ dlib::shared_ptr<base> p3;
+ dlib::shared_ptr<derived> p4;
+ DLIB_TEST(p4.get() == 0);
+ DLIB_TEST(p1);
+ DLIB_TEST(p2);
+ DLIB_TEST(!p3);
+ DLIB_TEST(!p4);
+ DLIB_TEST(p1.get() == realp1);
+ DLIB_TEST(p2.get() == realp2);
+ p1->num = 1;
+ p2->num = 2;
+ DLIB_TEST((*p1).num == 1);
+ DLIB_TEST((*p2).num == 2);
+
+ p1.swap(p3);
+ DLIB_TEST(!p1);
+ DLIB_TEST(p3);
+ DLIB_TEST((*p3).num == 1);
+ DLIB_TEST(p3->num == 1);
+ swap(p1,p3);
+ DLIB_TEST(p1);
+ DLIB_TEST(!p3);
+ DLIB_TEST((*p1).num == 1);
+ DLIB_TEST(p1->num == 1);
+ DLIB_TEST_MSG(counter == 2,counter);
+
+ DLIB_TEST(p1.unique());
+ DLIB_TEST(p2.unique());
+ DLIB_TEST(!p3.unique());
+ DLIB_TEST(!p4.unique());
+
+ DLIB_TEST(p1.use_count() == 1);
+ DLIB_TEST(p2.use_count() == 1);
+ DLIB_TEST(p3.use_count() == 0);
+ DLIB_TEST(p4.use_count() == 0);
+
+ dlib::shared_ptr<base> p11(p1);
+
+ DLIB_TEST(!p1.unique());
+ DLIB_TEST(p2.unique());
+ DLIB_TEST(!p3.unique());
+ DLIB_TEST(!p4.unique());
+
+ DLIB_TEST(p1.use_count() == 2);
+ DLIB_TEST(p2.use_count() == 1);
+ DLIB_TEST(p3.use_count() == 0);
+ DLIB_TEST(p4.use_count() == 0);
+
+ dlib::shared_ptr<base> p22(p2);
+
+ DLIB_TEST(!p1.unique());
+ DLIB_TEST(!p2.unique());
+ DLIB_TEST(!p3.unique());
+ DLIB_TEST(!p4.unique());
+
+ DLIB_TEST(p1.use_count() == 2);
+ DLIB_TEST(p2.use_count() == 2);
+ DLIB_TEST(p3.use_count() == 0);
+ DLIB_TEST(p4.use_count() == 0);
+
+ DLIB_TEST(p11.get() == realp1);
+ DLIB_TEST(p11 == p1);
+ DLIB_TEST(p22 == p2);
+ DLIB_TEST(p3 == p4);
+ DLIB_TEST(p11 != p22);
+ DLIB_TEST(p1 != p2);
+ DLIB_TEST(p3 != p1);
+ DLIB_TEST(p3 != p11);
+ DLIB_TEST(p3 != p2);
+
+
+ p1 = p1 = p1;
+ DLIB_TEST(p1.use_count() == 2);
+ DLIB_TEST(p1->num == 1);
+ DLIB_TEST(p11.use_count() == 2);
+ p1.reset();
+ DLIB_TEST(p1.get() == 0);
+ DLIB_TEST(p1.use_count() == 0);
+ DLIB_TEST(p1.unique() == false);
+ DLIB_TEST(p11.use_count() == 1);
+ p11 = p2;
+ DLIB_TEST(p1.use_count() == 0);
+ DLIB_TEST(p1.unique() == false);
+ DLIB_TEST(p11.use_count() == 3);
+ DLIB_TEST(p11.unique() == false);
+
+ // now p11, p2, and p22 all reference the same thing and the rest are null
+ DLIB_TEST_MSG((p11 < p2) == false,"");
+ DLIB_TEST_MSG((p2 < p11) == false,"");
+
+ DLIB_TEST(get_deleter<D>(p4) == 0);
+ p4 = p2;
+ DLIB_TEST(get_deleter<D>(p4) != 0);
+ DLIB_TEST(get_deleter<D>(p4) == get_deleter<D>(p2));
+ DLIB_TEST(get_deleter<D>(p4) == get_deleter<D>(p11));
+ DLIB_TEST(get_deleter<int>(p4) == 0);
+
+ realp1 = new derived;
+ p1.reset(realp1, &deleter_base);
+ DLIB_TEST(p1.get() == realp1);
+ DLIB_TEST(p1.unique());
+ DLIB_TEST(p1.use_count() == 1);
+ DLIB_TEST(*get_deleter<Db>(p1) == &deleter_base);
+ DLIB_TEST(p1 != p4);
+ p4 = dynamic_pointer_cast<derived>(p1);
+ DLIB_TEST(!p1.unique());
+ DLIB_TEST(p1.use_count() == 2);
+ DLIB_TEST(p1 == p4);
+
+ realp1 = new derived;
+ p1.reset(realp1);
+ DLIB_TEST(p1.get() == realp1);
+ DLIB_TEST(p1.unique());
+ DLIB_TEST(p1.use_count() == 1);
+ DLIB_TEST(get_deleter<D>(p1) == 0);
+
+
+ auto_ptr<derived> ap1(new derived);
+ auto_ptr<derived> ap2(new derived);
+ ap1->num = 35;
+ ap2->num = 36;
+
+ DLIB_TEST(ap1.get() != 0);
+ DLIB_TEST(ap2.get() != 0);
+ p1 = ap2;
+ p2 = ap1;
+
+ DLIB_TEST(ap1.get() == 0);
+ DLIB_TEST(p1.unique());
+ DLIB_TEST(p1.use_count() == 1);
+ DLIB_TEST(ap2.get() == 0);
+ DLIB_TEST(p2.unique());
+ DLIB_TEST(p2.use_count() == 1);
+ DLIB_TEST(p1->num == 36);
+ DLIB_TEST(p2->num == 35);
+
+ }
+
+ DLIB_TEST_MSG(counter == 0,counter);
+ DLIB_TEST_MSG(deleter_called == 2,counter);
+
+ dlib::weak_ptr<base> wp4;
+ {
+ dlib::shared_ptr<derived> p1(new derived, &deleter_base);
+ dlib::shared_ptr<derived> p2;
+ dlib::shared_ptr<base> p3;
+
+ dlib::weak_ptr<derived> wp1;
+ dlib::weak_ptr<base> wp2;
+ dlib::weak_ptr<base> wp3;
+
+ dlib::weak_ptr<derived> wp1c(p1);
+ dlib::weak_ptr<base> wp2c(p1);
+ dlib::weak_ptr<base> wp3c(p2);
+
+ DLIB_TEST(wp1c.use_count() == 1);
+ DLIB_TEST(wp1c.lock() == p1);
+ DLIB_TEST(wp1c.expired() == false);
+
+ DLIB_TEST(wp2c.use_count() == 1);
+ DLIB_TEST(wp2c.lock() == p1);
+ DLIB_TEST(wp2c.expired() == false);
+
+ DLIB_TEST(wp3c.use_count() == 0);
+ DLIB_TEST(wp3c.lock() == dlib::shared_ptr<base>());
+ DLIB_TEST(wp3c.expired() == true);
+
+ DLIB_TEST(wp2.use_count() == 0);
+ DLIB_TEST(wp2.expired() == true);
+ DLIB_TEST(wp2.lock().use_count() == 0);
+ DLIB_TEST(wp2.lock().unique() == false);
+
+ wp1 = p1;
+ wp2 = wp1;
+ wp3 = p1;
+
+ DLIB_TEST(p1.use_count() == 1);
+ DLIB_TEST(p1.unique());
+ DLIB_TEST(wp1.use_count() == 1);
+ DLIB_TEST(wp2.use_count() == 1);
+ DLIB_TEST(wp3.use_count() == 1);
+ DLIB_TEST(wp1.expired() == false);
+ DLIB_TEST(wp2.expired() == false);
+ DLIB_TEST(wp3.expired() == false);
+ DLIB_TEST(wp1.lock() == p1);
+ DLIB_TEST(wp2.lock() == p1);
+ DLIB_TEST(wp3.lock() == p1);
+
+ wp3.reset();
+
+ DLIB_TEST(p1.use_count() == 1);
+ DLIB_TEST(p1.unique());
+ DLIB_TEST(wp1.use_count() == 1);
+ DLIB_TEST(wp2.use_count() == 1);
+ DLIB_TEST(wp3.use_count() == 0);
+ DLIB_TEST(wp1.expired() == false);
+ DLIB_TEST(wp2.expired() == false);
+ DLIB_TEST(wp3.expired() == true);
+ DLIB_TEST(wp1.lock() == p1);
+ DLIB_TEST(wp2.lock() == p1);
+ DLIB_TEST(wp3.lock() == dlib::shared_ptr<base>());
+
+
+ p1.reset();
+
+ DLIB_TEST(p1.use_count() == 0);
+ DLIB_TEST(p1.unique() == false);
+ DLIB_TEST(wp1.use_count() == 0);
+ DLIB_TEST(wp2.use_count() == 0);
+ DLIB_TEST(wp3.use_count() == 0);
+ DLIB_TEST(wp1.expired() == true);
+ DLIB_TEST(wp2.expired() == true);
+ DLIB_TEST(wp3.expired() == true);
+ DLIB_TEST(wp1.lock() == dlib::shared_ptr<base>());
+ DLIB_TEST(wp2.lock() == dlib::shared_ptr<base>());
+ DLIB_TEST(wp3.lock() == dlib::shared_ptr<base>());
+
+ p1.reset(new derived);
+
+ DLIB_TEST(p1.use_count() == 1);
+ DLIB_TEST(p1.unique() == true);
+ DLIB_TEST(wp1.use_count() == 0);
+ DLIB_TEST(wp2.use_count() == 0);
+ DLIB_TEST(wp3.use_count() == 0);
+ DLIB_TEST(wp1.expired() == true);
+ DLIB_TEST(wp2.expired() == true);
+ DLIB_TEST(wp3.expired() == true);
+ DLIB_TEST(wp1.lock() == dlib::shared_ptr<base>());
+ DLIB_TEST(wp2.lock() == dlib::shared_ptr<base>());
+ DLIB_TEST(wp3.lock() == dlib::shared_ptr<base>());
+
+ DLIB_TEST(wp4.expired() == true);
+ DLIB_TEST(wp4.lock() == dlib::shared_ptr<base>());
+ wp4 = p1;
+ p3 = p1;
+ DLIB_TEST(wp4.expired() == false);
+ DLIB_TEST(wp4.lock() == p3);
+
+
+ bool ok = false;
+ try {
+ dlib::shared_ptr<base> bad_ptr(wp1);
+ } catch (dlib::bad_weak_ptr&)
+ {
+ ok = true;
+ }
+ DLIB_TEST(ok);
+ }
+ DLIB_TEST(wp4.expired() == true);
+ DLIB_TEST(wp4.lock() == dlib::shared_ptr<base>());
+
+
+ DLIB_TEST_MSG(counter == 0,counter);
+ DLIB_TEST_MSG(deleter_called == 3,counter);
+
+ {
+ scoped_ptr<int[]> a(new int[10]);
+
+ {
+ used_array_delete = false;
+ scoped_ptr<int[],test_deleter<int[]> > b(new int[10]);
+
+ for (int i = 0; i < 10; ++i)
+ {
+ a[i] = i;
+ b[i] = i;
+ }
+ }
+ DLIB_TEST(used_array_delete == true);
+
+
+ {
+ used_array_delete = true;
+ scoped_ptr<int,test_deleter<int> > c(new int);
+ }
+ DLIB_TEST(used_array_delete == false);
+
+ scoped_ptr<const int[]> const_a(new int[10]);
+
+ }
+
+ }
+
+
+
+ class smart_pointers_tester : public tester
+ {
+ public:
+ smart_pointers_tester (
+ ) :
+ tester ("test_smart_pointers",
+ "Runs tests on the smart pointers.")
+ {}
+
+ void perform_test (
+ )
+ {
+ smart_pointers_test();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/sockets.cpp b/ml/dlib/dlib/test/sockets.cpp
new file mode 100644
index 000000000..920fa9402
--- /dev/null
+++ b/ml/dlib/dlib/test/sockets.cpp
@@ -0,0 +1,247 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <cstdlib>
+#include <ctime>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include <dlib/sockets.h>
+#include <dlib/server.h>
+#include <dlib/misc_api.h>
+
+#include "tester.h"
+
+namespace {
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ dlib::mutex gm;
+ dlib::signaler gs(gm);
+ const char magic_num = 42;
+ const int min_bytes_sent = 10000;
+ int assigned_port;
+
+ logger dlog("test.sockets");
+
+// ----------------------------------------------------------------------------------------
+
+ class serv : public server::kernel_1a_c
+ {
+ public:
+ serv (
+ ) :
+ error_occurred (false),
+ got_connections(false)
+ {}
+
+ void on_listening_port_assigned (
+ )
+ {
+ auto_mutex M(gm);
+ assigned_port = get_listening_port();
+ gs.broadcast();
+ }
+
+
+ void on_connect (
+ connection& con
+ )
+ {
+ dlog << LINFO << "in serv::on_connect(): got new connection";
+ int status;
+ int count = 0;
+ char buf[100];
+ while ((status = con.read(buf,sizeof(buf))) > 0)
+ {
+ for (int i = 0; i < status; ++i)
+ {
+ if (buf[i] != magic_num)
+ {
+ tag = 4.0;
+ error_occurred = true;
+ }
+ }
+ count += status;
+ }
+ if (count != min_bytes_sent)
+ {
+ tag = 5.0;
+ error_occurred = true;
+ }
+ got_connections = true;
+ dlog << LINFO << "in serv::on_connect(): on_connect ending";
+ }
+
+ bool error_occurred;
+ bool got_connections;
+ double tag;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ class thread_container : public multithreaded_object
+ {
+ public:
+
+ serv& srv;
+
+ thread_container (
+ serv& srv_
+ ) : srv(srv_)
+ {
+ for (int i = 0; i < 10; ++i)
+ register_thread(*this, &thread_container::thread_proc);
+
+ // start up the threads
+ start();
+ }
+
+ ~thread_container ()
+ {
+ // wait for all threads to terminate
+ wait();
+ }
+
+ void thread_proc (
+ )
+ {
+ try
+ {
+ dlog << LTRACE << "enter thread";
+ {
+ auto_mutex M(gm);
+ while (assigned_port == 0)
+ gs.wait();
+ }
+
+ int status;
+ std::unique_ptr<connection> con;
+ string hostname;
+ string ip;
+ status = get_local_hostname(hostname);
+ if (status)
+ {
+ srv.tag = 1.0;
+ srv.error_occurred = true;
+ srv.clear();
+ dlog << LERROR << "leaving thread, line: " << __LINE__;
+ dlog << LERROR << "get_local_hostname() failed";
+ return;
+ }
+
+ status = hostname_to_ip(hostname,ip);
+ if (status)
+ {
+ srv.tag = 2.0;
+ srv.error_occurred = true;
+ srv.clear();
+ dlog << LERROR << "leaving thread, line: " << __LINE__;
+ dlog << LERROR << "hostname_to_ip() failed";
+ return;
+ }
+
+ dlog << LTRACE << "try to connect to the server at port " << srv.get_listening_port();
+ status = create_connection(con,srv.get_listening_port(),ip);
+ if (status)
+ {
+ srv.tag = 3.0;
+ srv.error_occurred = true;
+ srv.clear();
+ dlog << LERROR << "leaving thread, line: " << __LINE__;
+ dlog << LERROR << "create_connection() failed";
+ return;
+ }
+
+ dlog << LTRACE << "sending magic_num to server";
+ int i;
+ for (i = 0; i < min_bytes_sent; ++i)
+ {
+ con->write(&magic_num,1);
+ }
+
+ dlog << LTRACE << "shutting down connection to server";
+ close_gracefully(con);
+ dlog << LTRACE << "finished calling close_gracefully() on the connection";
+ }
+ catch (exception& e)
+ {
+ srv.error_occurred = true;
+ dlog << LERROR << "exception thrown in thread_proc(): " << e.what();
+ cout << "exception thrown in thread_proc(): " << e.what();
+ }
+ dlog << LTRACE << "exit thread";
+ }
+ };
+
+ void run_server(serv* srv)
+ {
+ dlog << LTRACE << "calling srv.start()";
+ srv->start();
+ dlog << LTRACE << "srv.start() just ended.";
+ }
+
+ void sockets_test (
+ )
+ /*!
+ requires
+ - sockets is an implementation of sockets/sockets_kernel_abstract.h
+ is instantiated with int
+ ensures
+ - runs tests on sockets for compliance with the specs
+ !*/
+ {
+
+ dlog << LTRACE << "starting test";
+ serv srv;
+
+ assigned_port = 0;
+
+
+ dlog << LTRACE << "spawning threads";
+ thread_container stuff(srv);
+
+
+
+ thread_function thread2(run_server, &srv);
+
+ // wait until all the sending threads have ended
+ stuff.wait();
+
+ if (srv.error_occurred)
+ {
+ dlog << LDEBUG << "tag: " << srv.tag;
+ }
+
+ srv.clear();
+
+ dlog << LTRACE << "ending successful test";
+ DLIB_TEST( !srv.error_occurred);
+ DLIB_TEST( srv.got_connections);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+
+ class sockets_tester : public tester
+ {
+ public:
+ sockets_tester (
+ ) :
+ tester ("test_sockets",
+ "Runs tests on the sockets component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ sockets_test();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/sockets2.cpp b/ml/dlib/dlib/test/sockets2.cpp
new file mode 100644
index 000000000..3521e751d
--- /dev/null
+++ b/ml/dlib/dlib/test/sockets2.cpp
@@ -0,0 +1,204 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <algorithm>
+#include <memory>
+
+#include "tester.h"
+#include <dlib/sockets.h>
+#include <dlib/threads.h>
+#include <dlib/array.h>
+
+// This is called an unnamed-namespace and it has the effect of making everything
+// inside this file "private" so that everything you declare will have static linkage.
+// Thus we won't have any multiply defined symbol errors coming out of the linker when
+// we try to compile the test suite.
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ // Declare the logger we will use in this test. The name of the logger
+ // should start with "test."
+ dlib::logger dlog("test.sockets2");
+
+
+ class sockets2_tester : public tester, private multithreaded_object
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+
+ short port_num;
+ string data_to_send;
+
+ bool test_failed;
+
+ void write_thread (
+ )
+ {
+ try
+ {
+ std::unique_ptr<connection> con(connect("127.0.0.1", port_num));
+
+ // Send a copy of the data down the connection so we can test our the read() function
+ // that uses timeouts in the main thread.
+ if (con->write(data_to_send.data(), data_to_send.size()) != (int)data_to_send.size())
+ {
+ test_failed = true;
+ dlog << LERROR << "failed to send all the data down the connection";
+ }
+
+ close_gracefully(con,300000);
+ }
+ catch (exception& e)
+ {
+ test_failed = true;
+ dlog << LERROR << e.what();
+ }
+ }
+
+ void no_write_thread (
+ )
+ {
+ try
+ {
+ std::unique_ptr<connection> con(connect("127.0.0.1", port_num));
+
+ // just do nothing until the connection closes
+ char ch;
+ con->read(&ch, 1);
+ dlog << LDEBUG << "silent connection finally closing";
+ }
+ catch (exception& e)
+ {
+ test_failed = true;
+ dlog << LERROR << e.what();
+ }
+ }
+
+ public:
+ sockets2_tester (
+ ) :
+ tester (
+ "test_sockets2", // the command line argument name for this test
+ "Run sockets2 tests.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ register_thread(*this, &sockets2_tester::write_thread);
+ register_thread(*this, &sockets2_tester::write_thread);
+ register_thread(*this, &sockets2_tester::write_thread);
+ register_thread(*this, &sockets2_tester::write_thread);
+ register_thread(*this, &sockets2_tester::write_thread);
+ register_thread(*this, &sockets2_tester::no_write_thread);
+ }
+
+ void perform_test (
+ )
+ {
+ run_tests(0);
+ run_tests(40);
+ }
+
+ void run_tests (
+ unsigned long timeout_to_use
+ )
+ {
+ // make sure there aren't any threads running
+ wait();
+
+ port_num = 5000;
+ test_failed = false;
+
+ print_spinner();
+ data_to_send = "oi 2m3ormao2m fo2im3fo23mi o2mi3 foa2m3fao23ifm2o3fmia23oima23iom3giugbiua";
+ // make the block of data much larger
+ for (int i = 0; i < 11; ++i)
+ data_to_send = data_to_send + data_to_send;
+
+ dlog << LINFO << "data block size: " << data_to_send.size();
+
+
+ std::unique_ptr<listener> list;
+ DLIB_TEST(create_listener(list, port_num, "127.0.0.1") == 0);
+ DLIB_TEST(bool(list));
+
+ // kick off the sending threads
+ start();
+
+
+ dlib::array<std::unique_ptr<connection> > cons;
+ std::vector<long> bytes_received(6,0);
+ std::unique_ptr<connection> con_temp;
+
+ // accept the 6 connections we should get
+ for (int i = 0; i < 6; ++i)
+ {
+ DLIB_TEST(list->accept(con_temp) == 0);
+ cons.push_back(con_temp);
+ print_spinner();
+ }
+
+ int finished_cons = 0;
+
+ // now receive all the bytes from the sending threads
+ while (finished_cons < 5)
+ {
+ for (unsigned long i = 0; i < cons.size(); ++i)
+ {
+ if (cons[i])
+ {
+ const int buf_size = 3000;
+ char buf[buf_size];
+
+ int status = cons[i]->read(buf, buf_size, timeout_to_use);
+
+ if (status > 0)
+ {
+ DLIB_TEST(equal(buf, buf+status, data_to_send.begin()+bytes_received[i]));
+ bytes_received[i] += status;
+ }
+ else if (status == 0)
+ {
+ // the connection is closed to kill it
+ cons[i].reset();
+ ++finished_cons;
+ }
+ }
+ }
+ print_spinner();
+ }
+
+ for (unsigned long i = 0; i < bytes_received.size(); ++i)
+ {
+ DLIB_TEST(bytes_received[i] == (long)data_to_send.size() || cons[i]);
+ }
+
+
+ dlog << LINFO << "All data received correctly";
+
+ cons.clear();
+
+
+ print_spinner();
+
+ DLIB_TEST(test_failed == false);
+
+
+ // wait for all the sending threads to terminate
+ wait();
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ sockets2_tester a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/sockstreambuf.cpp b/ml/dlib/dlib/test/sockstreambuf.cpp
new file mode 100644
index 000000000..519feb2b5
--- /dev/null
+++ b/ml/dlib/dlib/test/sockstreambuf.cpp
@@ -0,0 +1,253 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <cstdlib>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <ctime>
+#include <dlib/sockets.h>
+#include <dlib/misc_api.h>
+#include <dlib/sockstreambuf.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ dlib::mutex m;
+ dlib::signaler s(m);
+ bool thread_running;
+
+ logger dlog("test.sockstreambuf");
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename ssb>
+ struct thread_proc_struct
+ {
+ static void thread_proc (
+ void* param
+ )
+ {
+
+ listener& list = *static_cast<listener*>(param);
+ connection* con;
+ list.accept(con);
+
+ ssb buf(con);
+ ostream out(&buf);
+
+
+ char ch;
+ char* bigbuf = new char[1000000];
+
+
+ for (int i = 'a'; i < 'z'; ++i)
+ {
+ ch = i;
+ out << ch << " ";
+ }
+
+ out.put('A');
+
+ for (int i = 0; i < 256; ++i)
+ {
+ ch = i;
+ out.write(&ch,1);
+ }
+
+ for (int i = -100; i < 25600; ++i)
+ {
+ out << i << " ";
+ }
+
+ out.put('A');
+
+ for (int i = -100; i < 25600; ++i)
+ {
+ out.write((char*)&i,sizeof(i));
+ }
+
+ for (int i = 0; i < 1000000; ++i)
+ {
+ bigbuf[i] = (i&0xFF);
+ }
+ out.write(bigbuf,1000000);
+
+ out.put('d');
+ out.put('a');
+ out.put('v');
+ out.put('i');
+ out.put('s');
+
+
+ string tstring = "this is a test";
+ int tint = -853;
+ unsigned int tuint = 89;
+ serialize(tstring,out);
+ serialize(tint,out);
+ serialize(tuint,out);
+
+
+ out.flush();
+
+
+ auto_mutex M(m);
+ thread_running = false;
+ s.signal();
+
+ dlib::sleep(300);
+ delete con;
+ delete &list;
+
+ delete [] bigbuf;
+ }
+ };
+
+ template <typename ssb>
+ void sockstreambuf_test (
+ )
+ /*!
+ requires
+ - ssb is an implementation of sockstreambuf/sockstreambuf_kernel_abstract.h
+ ensures
+ - runs tests on ssb for compliance with the specs
+ !*/
+ {
+ char ch;
+ vector<char> vbuf;
+ vbuf.resize(1000000);
+ char* bigbuf = &vbuf[0];
+ connection* con;
+
+ print_spinner();
+ thread_running = true;
+ listener* list;
+ if (create_listener(list,0))
+ {
+ DLIB_TEST_MSG(false, "Unable to create a listener");
+ }
+
+ create_new_thread(&thread_proc_struct<ssb>::thread_proc,list);
+
+ if (create_connection(con,list->get_listening_port(),"127.0.0.1"))
+ {
+ DLIB_TEST_MSG(false, "Unable to create a connection");
+ }
+
+ // make sure con gets deleted
+ std::unique_ptr<connection> del_con(con);
+
+ ssb buf(con);
+ istream in(&buf);
+
+
+
+ for (int i = 'a'; i < 'z'; ++i)
+ {
+ in >> ch;
+ char c = i;
+ DLIB_TEST_MSG(ch == c,"ch: " << (int)ch << " c: " << (int)c);
+ }
+
+ in.get();
+ DLIB_TEST_MSG(in.peek() == 'A', "*" << in.peek() << "*");
+ in.get();
+
+ for (int i = 0; i < 256; ++i)
+ {
+ in.read(&ch,1);
+ char c = i;
+ DLIB_TEST_MSG(ch == c,"ch: " << (int)ch << " c: " << (int)c );
+ }
+
+ for (int i = -100; i < 25600; ++i)
+ {
+ int n = 0;
+ in >> n;
+ DLIB_TEST_MSG(n == i,"n: " << n << " i:" << i);
+ }
+
+ in.get();
+ DLIB_TEST_MSG(in.peek() == 'A', "*" << in.peek() << "*");
+ in.get();
+
+ for (int i = -100; i < 25600; ++i)
+ {
+ int n;
+ in.read((char*)&n,sizeof(n));
+ DLIB_TEST_MSG(n == i,"n: " << n << " i:" << i);
+ }
+
+ in.read(bigbuf,1000000);
+ for (int i = 0; i < 1000000; ++i)
+ {
+ DLIB_TEST(bigbuf[i] == (char)(i&0xFF));
+ }
+
+ DLIB_TEST(in.get() == 'd');
+ DLIB_TEST(in.get() == 'a');
+ DLIB_TEST(in.get() == 'v');
+ DLIB_TEST(in.get() == 'i');
+
+ DLIB_TEST(in.peek() == 's');
+
+ DLIB_TEST(in.get() == 's');
+
+ in.putback('s');
+ DLIB_TEST(in.peek() == 's');
+
+ DLIB_TEST(in.get() == 's');
+
+
+ string tstring;
+ int tint;
+ unsigned int tuint;
+ deserialize(tstring,in);
+ deserialize(tint,in);
+ deserialize(tuint,in);
+
+ DLIB_TEST(tstring == "this is a test");
+ DLIB_TEST(tint == -853);
+ DLIB_TEST(tuint == 89);
+
+
+
+ auto_mutex M(m);
+ while (thread_running)
+ s.wait();
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+
+ class sockstreambuf_tester : public tester
+ {
+ public:
+ sockstreambuf_tester (
+ ) :
+ tester ("test_sockstreambuf",
+ "Runs tests on the sockstreambuf component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing sockstreambuf";
+ sockstreambuf_test<sockstreambuf>();
+ dlog << LINFO << "testing sockstreambuf_unbuffered";
+ sockstreambuf_test<sockstreambuf_unbuffered>();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/sparse_vector.cpp b/ml/dlib/dlib/test/sparse_vector.cpp
new file mode 100644
index 000000000..97b60b7b3
--- /dev/null
+++ b/ml/dlib/dlib/test/sparse_vector.cpp
@@ -0,0 +1,301 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <dlib/sparse_vector.h>
+#include "tester.h"
+#include <dlib/rand.h>
+#include <dlib/string.h>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.sparse_vector");
+
+ void test_sparse_matrix_vector_multiplies()
+ {
+ dlib::rand rnd;
+
+ const long size = 30;
+
+ for (int iter = 0; iter < 10; ++iter)
+ {
+ print_spinner();
+
+ std::vector<sample_pair> edges;
+ std::vector<ordered_sample_pair> oedges;
+ matrix<double> M(size,size);
+ M = 0;
+ for (long i = 0; i < M.size()/3; ++i)
+ {
+ const long r = rnd.get_random_32bit_number()%M.nr();
+ const long c = rnd.get_random_32bit_number()%M.nc();
+ const double d = rnd.get_random_gaussian()*10;
+ M(r,c) += d;
+ oedges.push_back(ordered_sample_pair(r,c,d));
+ }
+
+ matrix<double> SM(size,size);
+ SM = 0;
+ for (long i = 0; i < SM.size()/3; ++i)
+ {
+ const long r = rnd.get_random_32bit_number()%SM.nr();
+ const long c = rnd.get_random_32bit_number()%SM.nc();
+ const double d = rnd.get_random_gaussian()*10;
+ SM(r,c) += d;
+ if (r != c)
+ SM(c,r) += d;
+ edges.push_back(sample_pair(r,c,d));
+ }
+
+ const matrix<double> v = randm(size,1);
+
+ matrix<double> result;
+
+ sparse_matrix_vector_multiply(oedges, v, result);
+ DLIB_TEST_MSG(length(M*v - result) < 1e-12, length(M*v - result));
+
+ sparse_matrix_vector_multiply(edges, v, result);
+ DLIB_TEST_MSG(length(SM*v - result) < 1e-12, length(SM*v - result));
+
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_sparse_matrix_vector_multiply1()
+ {
+ print_spinner();
+ std::map<unsigned long,double> sv;
+ sv[2] = 8;
+ sv[6] = 2.3;
+
+ matrix<double,10,1> v;
+ v = 0;
+ v(2) = 8;
+ v(6) = 2.3;
+
+
+ matrix<double,0,1> r1, r2;
+
+ r1 = gaussian_randm(4,10)*v;
+ r2 = sparse_matrix_vector_multiply(gaussian_randm(4,std::numeric_limits<long>::max()),sv);
+
+ DLIB_TEST(max(abs(r1-r2)) < 1e-15);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_sparse_matrix_vector_multiply2()
+ {
+ std::vector<std::pair<unsigned long,double> > sv;
+ sv.push_back(make_pair(6, 1.42));
+ sv.push_back(make_pair(3, 5));
+
+ matrix<double,9,1> v;
+ v = 0;
+ v(3) = 5;
+ v(6) = 1.42;
+
+
+ matrix<double,0,1> r1, r2;
+
+ r1 = gaussian_randm(3,9)*v;
+ r2 = sparse_matrix_vector_multiply(gaussian_randm(3,std::numeric_limits<long>::max()),sv);
+
+ DLIB_TEST(max(abs(r1-r2)) < 1e-15);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_make_sparse_vector_inplace()
+ {
+ std::vector<std::pair<unsigned long,double> > vect;
+ vect.push_back(make_pair(4,1));
+ vect.push_back(make_pair(0,1));
+ vect.push_back(make_pair(4,1));
+ vect.push_back(make_pair(3,1));
+ vect.push_back(make_pair(8,1));
+ vect.push_back(make_pair(8,1));
+ vect.push_back(make_pair(8,1));
+ vect.push_back(make_pair(8,1));
+
+ make_sparse_vector_inplace(vect);
+
+ DLIB_TEST(vect.size() == 4);
+ DLIB_TEST(vect[0].first == 0);
+ DLIB_TEST(vect[1].first == 3);
+ DLIB_TEST(vect[2].first == 4);
+ DLIB_TEST(vect[3].first == 8);
+
+ DLIB_TEST(vect[0].second == 1);
+ DLIB_TEST(vect[1].second == 1);
+ DLIB_TEST(vect[2].second == 2);
+ DLIB_TEST(vect[3].second == 4);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class sparse_vector_tester : public tester
+ {
+ public:
+ sparse_vector_tester (
+ ) :
+ tester (
+ "test_sparse_vector", // the command line argument name for this test
+ "Run tests on the sparse_vector routines.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+
+ void perform_test (
+ )
+ {
+ test_make_sparse_vector_inplace();
+
+ std::map<unsigned int, double> v;
+ v[4] = 8;
+ v[2] = -4;
+ v[9] = 10;
+
+ DLIB_TEST(max(v) == 10);
+ DLIB_TEST(min(v) == -4);
+
+ v.clear();
+ v[4] = 8;
+ v[9] = 10;
+ DLIB_TEST(max(v) == 10);
+ DLIB_TEST(min(v) == 0);
+
+
+ v.clear();
+ v[4] = -9;
+ v[9] = -4;
+ DLIB_TEST(max(v) == 0);
+ DLIB_TEST(min(v) == -9);
+
+
+ {
+ matrix<double> a(2,2), b(2,2);
+ a = randm(2,2);
+ b = randm(2,2);
+
+ DLIB_TEST(equal(a-b, subtract(a,b)));
+ DLIB_TEST(equal(a+b, add(a,b)));
+ DLIB_TEST(equal(a-(b+b), subtract(a,b+b)));
+ DLIB_TEST(equal(a+b+b, add(a,b+b)));
+ }
+
+ {
+ std::map<unsigned long,double> a, b, c;
+ a[1] = 2;
+ a[3] = 5;
+
+ b[0] = 3;
+ b[1] = 1;
+
+ c = add(a,b);
+ DLIB_TEST(c.size() == 3);
+ DLIB_TEST(c[0] == 3);
+ DLIB_TEST(c[1] == 3);
+ DLIB_TEST(c[3] == 5);
+
+ c = subtract(a,b);
+ DLIB_TEST(c.size() == 3);
+ DLIB_TEST(c[0] == -3);
+ DLIB_TEST(c[1] == 1);
+ DLIB_TEST(c[3] == 5);
+
+ c = add(b,a);
+ DLIB_TEST(c.size() == 3);
+ DLIB_TEST(c[0] == 3);
+ DLIB_TEST(c[1] == 3);
+ DLIB_TEST(c[3] == 5);
+
+ c = subtract(b,a);
+ DLIB_TEST(c.size() == 3);
+ DLIB_TEST(c[0] == 3);
+ DLIB_TEST(c[1] == -1);
+ DLIB_TEST(c[3] == -5);
+
+ std::vector<std::pair<unsigned long,double> > aa, bb, cc;
+
+ aa.assign(a.begin(), a.end());
+ bb.assign(b.begin(), b.end());
+
+ cc = add(aa,bb);
+ DLIB_TEST(cc.size() == 3);
+ DLIB_TEST(cc[0].first == 0);
+ DLIB_TEST(cc[1].first == 1);
+ DLIB_TEST(cc[2].first == 3);
+ DLIB_TEST(cc[0].second == 3);
+ DLIB_TEST(cc[1].second == 3);
+ DLIB_TEST(cc[2].second == 5);
+
+ cc = subtract(aa,bb);
+ DLIB_TEST(cc.size() == 3);
+ DLIB_TEST(cc[0].first == 0);
+ DLIB_TEST(cc[1].first == 1);
+ DLIB_TEST(cc[2].first == 3);
+ DLIB_TEST(cc[0].second == -3);
+ DLIB_TEST(cc[1].second == 1);
+ DLIB_TEST(cc[2].second == 5);
+
+ cc = add(bb,aa);
+ DLIB_TEST(cc.size() == 3);
+ DLIB_TEST(cc[0].first == 0);
+ DLIB_TEST(cc[1].first == 1);
+ DLIB_TEST(cc[2].first == 3);
+ DLIB_TEST(cc[0].second == 3);
+ DLIB_TEST(cc[1].second == 3);
+ DLIB_TEST(cc[2].second == 5);
+
+ cc = subtract(bb,aa);
+ DLIB_TEST(cc.size() == 3);
+ DLIB_TEST(cc[0].first == 0);
+ DLIB_TEST(cc[1].first == 1);
+ DLIB_TEST(cc[2].first == 3);
+ DLIB_TEST(cc[0].second == 3);
+ DLIB_TEST(cc[1].second == -1);
+ DLIB_TEST(cc[2].second == -5);
+
+ }
+
+ test_sparse_matrix_vector_multiplies();
+ test_sparse_matrix_vector_multiply1();
+ test_sparse_matrix_vector_multiply2();
+
+ {
+ matrix<double,0,1> a, b;
+ a = gaussian_randm(6,1, 0);
+ b = gaussian_randm(6,1, 1);
+
+ std::vector<std::pair<unsigned long,double> > aa, bb;
+
+ assign(aa, a);
+ assign(bb, b);
+
+ // dot() does something special when the sparse vectors have entries for
+ // each dimension, which is what happens when they are copied from dense
+ // vectors. So the point of the tests in this block is to make sure dot()
+ // works right in this case.
+ DLIB_TEST(std::abs(dot(a,b) - dot(aa,bb)) < 1e-14);
+ a(3) = 0;
+ assign(aa, a);
+ DLIB_TEST(std::abs(dot(a,b) - dot(aa,bb)) < 1e-14);
+ }
+ }
+ };
+
+ sparse_vector_tester a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/stack.cpp b/ml/dlib/dlib/test/stack.cpp
new file mode 100644
index 000000000..0b92eaeb9
--- /dev/null
+++ b/ml/dlib/dlib/test/stack.cpp
@@ -0,0 +1,294 @@
+// Copyright (C) 2005 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/stack.h>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.stack");
+
+ template <
+ typename stack
+ >
+ void stack_kernel_test (
+ )
+ /*!
+ requires
+ - stack is an implementation of stack/stack_sort_abstract.h
+ stack is instantiated with int
+ ensures
+ - runs tests on stack for compliance with the specs
+ !*/
+ {
+
+
+ srand(static_cast<unsigned int>(time(0)));
+
+ print_spinner();
+
+ stack a1, a2;
+
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ swap(a1,a2);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.move_next() == false);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.size() == 0);
+
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ a1.reset();
+ a2.reset();
+
+ for (unsigned long k = 0; k < 4; ++k)
+ {
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ swap(a1,a2);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.move_next() == false);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.size() == 0);
+
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ a1.clear();
+ a2.clear();
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ swap(a1,a2);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.move_next() == false);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.size() == 0);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a2.size() == 0);
+
+
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start());
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.move_next() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a1.at_start() == false);
+ DLIB_TEST(a1.size() == 0);
+
+ a1.clear();
+ a2.clear();
+
+
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ int a = (int)i;
+ a1.push(a);
+ }
+
+ DLIB_TEST(a1.size() == 100);
+
+ int count = 99;
+ while (a1.move_next())
+ {
+ DLIB_TEST_MSG(a1.element() == count,a1.element() << " : " << count);
+ --count;
+ }
+
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == false);
+
+ a1.swap(a2);
+
+ count = 99;
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == false);
+ DLIB_TEST(a1.current_element_valid() == false);
+ DLIB_TEST(a1.at_start() == true);
+
+ DLIB_TEST(a1.size() == 0);
+ DLIB_TEST(a2.size() == 100);
+ DLIB_TEST(a2.current() == 99);
+
+ a2.reset();
+ while (a2.move_next())
+ {
+ DLIB_TEST(a2.element() == count--);
+ }
+
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == false);
+ int b = 4;
+ a2.push(b);
+ DLIB_TEST(a2.current_element_valid() == false);
+ DLIB_TEST(a2.at_start() == true);
+
+ DLIB_TEST(a2.current() == 4);
+ int c = 0;
+ a2.pop(c);
+ DLIB_TEST(c == 4);
+
+ // serialize the state of a2, then clear a2, then
+ // load the state back into a2.
+ ostringstream sout;
+ serialize(a2,sout);
+ DLIB_TEST(a2.at_start() == true);
+ istringstream sin(sout.str());
+ a2.clear();
+ deserialize(a2,sin);
+
+
+ count = 99;
+ while (a2.size())
+ {
+ int a = 0;
+ DLIB_TEST(a2.current() == count);
+ DLIB_TEST(const_cast<const stack&>(a2).current() == count);
+ a2.pop(a);
+ DLIB_TEST(a == count--);
+ }
+
+
+
+
+
+
+ a1.clear();
+ a2.clear();
+ }
+
+
+ {
+ a1.clear();
+ remover<int>& go = a1;
+ for (int i = 0; i < 100; ++i)
+ {
+ int a = 3;
+ a1.push(a);
+ }
+ DLIB_TEST(go.size() == 100);
+ for (int i = 0; i < 100; ++i)
+ {
+ int a = 9;
+ a1.remove_any(a);
+ DLIB_TEST(a == 3);
+ }
+ DLIB_TEST(go.size() == 0);
+ }
+
+ }
+
+
+
+
+ class stack_tester : public tester
+ {
+ public:
+ stack_tester (
+ ) :
+ tester ("test_stack",
+ "Runs tests on the stack component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ stack_kernel_test<stack<int>::kernel_1a> ();
+ dlog << LINFO << "testing kernel_1a_c";
+ stack_kernel_test<stack<int>::kernel_1a_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/static_map.cpp b/ml/dlib/dlib/test/static_map.cpp
new file mode 100644
index 000000000..931ae1fae
--- /dev/null
+++ b/ml/dlib/dlib/test/static_map.cpp
@@ -0,0 +1,323 @@
+// Copyright (C) 2005 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/hash_table.h>
+#include <dlib/binary_search_tree.h>
+
+#include <dlib/static_map.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.static_map");
+
+ template <
+ typename map
+ >
+ void static_map_kernel_test (
+ )
+ /*!
+ requires
+ - map is an implementation of static_map/static_map_kernel_abstract.h and
+ is instantiated to map int to int
+ ensures
+ - runs tests on map for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+ srand(static_cast<unsigned int>(time(0)));
+
+ typedef binary_search_tree<int,int>::kernel_2a_c bst;
+ typedef hash_table<int,int>::kernel_1a_c ht;
+
+ const unsigned long table_4_max_size = 100;
+ const unsigned long tree_max_size = 50000;
+ ht table_4(4);
+ ht table_8(8);
+ bst tree;
+
+ ht table_4b(4);
+ ht table_8b(8);
+ bst treeb;
+
+
+ // just do the following to make sure operator[] doesn't hang
+ // under some instances
+ {
+ int g = 1, h = 1;
+ treeb.add(g,h);
+ map test;
+ map test2;
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test.at_start());
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.move_next() == false);
+ DLIB_TEST(test.current_element_valid() == false);
+ DLIB_TEST(test.at_start() == false);
+
+ swap(test,test2);
+ DLIB_TEST(test2.at_start() == false);
+ DLIB_TEST(test.at_start() == true);
+
+ swap(test,test2);
+ DLIB_TEST(test.at_start() == false);
+
+
+ DLIB_TEST(test.size() == 0);
+ DLIB_TEST(test[1] == 0);
+ DLIB_TEST(test[2] == 0);
+ DLIB_TEST(test[3] == 0);
+ DLIB_TEST(test[0] == 0);
+
+ test.load(treeb);
+ DLIB_TEST(test.at_start());
+ DLIB_TEST(test[1] != 0);
+ DLIB_TEST(test[2] == 0);
+ DLIB_TEST(test[3] == 0);
+ DLIB_TEST(test[0] == 0);
+
+ test2.clear();
+ swap(test2,test);
+ DLIB_TEST(test2[1] != 0);
+ DLIB_TEST(test2[2] == 0);
+ DLIB_TEST(test2[3] == 0);
+ DLIB_TEST(test2[0] == 0);
+ DLIB_TEST(test[1] == 0);
+ DLIB_TEST(test[2] == 0);
+ DLIB_TEST(test[3] == 0);
+ DLIB_TEST(test[0] == 0);
+
+
+ DLIB_TEST(treeb.size() == 0);
+ treeb.clear();
+ }
+
+
+ for (unsigned long i = 0; i < table_4_max_size; ++i)
+ {
+ int a = ::rand()&0xFF;
+ int b = a + 1;
+ int ab = a;
+ int bb = b;
+ table_4.add(a,b);
+ table_4b.add(ab,bb);
+ }
+
+ for (unsigned long i = 0; i < table_4_max_size; ++i)
+ {
+ int a = ::rand()&0xF;
+ int b = a + 1;
+ int ab = a;
+ int bb = b;
+ table_8.add(a,b);
+ table_8b.add(ab,bb);
+ }
+
+ for (unsigned long i = 0; i < tree_max_size; ++i)
+ {
+ int a = ::rand()&0xFFF;
+ int b = a + 1;
+ int ab = a;
+ int bb = b;
+ tree.add(a,b);
+ treeb.add(ab,bb);
+ }
+
+ map m_4;
+ m_4.load(table_4);
+ map m_8;
+ m_8.load(table_8);
+ map m_t;
+ m_t.load(tree);
+ map e;
+ e.load(table_4);
+
+ DLIB_TEST(e.size() == 0);
+ DLIB_TEST(e.at_start() == true);
+ DLIB_TEST(e.current_element_valid() == false);
+ DLIB_TEST(e.move_next() == false);
+ DLIB_TEST(e.at_start() == false);
+ DLIB_TEST(e.current_element_valid() == false);
+
+ DLIB_TEST(m_4.size() == table_4b.size());
+ DLIB_TEST(m_8.size() == table_8b.size());
+ DLIB_TEST(m_t.size() == treeb.size());
+
+ DLIB_TEST(m_4.at_start() == true);
+ DLIB_TEST(m_8.at_start() == true);
+ DLIB_TEST(m_t.at_start() == true);
+ DLIB_TEST(m_4.current_element_valid() == false);
+ DLIB_TEST(m_8.current_element_valid() == false);
+ DLIB_TEST(m_t.current_element_valid() == false);
+
+
+ DLIB_TEST(m_4.move_next() == true);
+ DLIB_TEST(m_4.at_start() == false);
+ DLIB_TEST(m_4.current_element_valid() == true);
+ DLIB_TEST(m_8.move_next() == true);
+ DLIB_TEST(m_8.at_start() == false);
+ DLIB_TEST(m_8.current_element_valid() == true);
+ DLIB_TEST(m_t.move_next() == true);
+ DLIB_TEST(m_t.at_start() == false);
+ DLIB_TEST(m_t.current_element_valid() == true);
+
+ m_4.reset();
+ m_8.reset();
+ m_t.reset();
+
+ while (m_4.move_next())
+ {
+ DLIB_TEST( table_4b[m_4.element().key()] != 0);
+ DLIB_TEST( *table_4b[m_4.element().key()] == m_4.element().value());
+ }
+
+ // serialize the state of m_4, then clear m_4, then
+ // load the state back into m_4.
+ ostringstream sout;
+ serialize(m_4,sout);
+ DLIB_TEST(m_4.at_start() == true);
+ istringstream sin(sout.str());
+ m_4.clear();
+ deserialize(m_4,sin);
+ DLIB_TEST(m_4.at_start() == true);
+
+
+
+ while (table_4b.move_next())
+ {
+ DLIB_TEST( m_4[table_4b.element().key()] != 0);
+ DLIB_TEST( *m_4[table_4b.element().key()] == table_4b.element().value());
+ }
+
+ // serialize the state of m_8, then clear m_8, then
+ // load the state back into m_8.
+ sout.str("");
+ serialize(m_8,sout);
+ DLIB_TEST(m_8.at_start() == true);
+ sin.str(sout.str());
+ m_8.clear();
+ deserialize(m_8,sin);
+ DLIB_TEST(m_8.at_start() == true);
+
+ while (m_8.move_next())
+ {
+ DLIB_TEST( table_8b[m_8.element().key()] != 0);
+ DLIB_TEST( *table_8b[m_8.element().key()] == m_8.element().value());
+ }
+
+ while (table_8b.move_next())
+ {
+ DLIB_TEST( m_8[table_8b.element().key()] != 0);
+ DLIB_TEST( *m_8[table_8b.element().key()] == table_8b.element().value());
+ }
+
+
+ while (m_t.move_next())
+ {
+ DLIB_TEST( treeb[m_t.element().key()] != 0);
+ DLIB_TEST( *treeb[m_t.element().key()] == m_t.element().value());
+ }
+
+ // make sure operator[] doesn't hang
+ for (int l = 1; l < 10000; ++l)
+ {
+ DLIB_TEST(m_t[l+0xFFF] == 0);
+ }
+
+ while (treeb.move_next())
+ {
+ DLIB_TEST( m_t[treeb.element().key()] != 0);
+ DLIB_TEST( *m_t[treeb.element().key()] == treeb.element().value());
+ }
+
+
+
+ m_4.reset();
+ m_8.reset();
+ m_t.reset();
+
+ int last = 0;
+ while (m_4.move_next())
+ {
+ DLIB_TEST(last <= m_4.element().key());
+ DLIB_TEST(m_4.element().key() + 1 == m_4.element().value());
+ last = m_4.element().key();
+ }
+
+ last = 0;
+ while (m_8.move_next())
+ {
+ DLIB_TEST(last <= m_8.element().key());
+ DLIB_TEST(m_8.element().key() + 1 == m_8.element().value());
+ last = m_8.element().key();
+ }
+
+ last = 0;
+ while (m_t.move_next())
+ {
+ DLIB_TEST(last <= m_t.element().key());
+ DLIB_TEST(m_t.element().key() + 1 == m_t.element().value());
+ last = m_t.element().key();
+ }
+
+
+
+
+
+
+ // this is just to test swap
+ m_4.swap(m_8);
+ m_4.reset();
+ table_4b.reset();
+ while (m_8.move_next())
+ {
+ DLIB_TEST( table_4b[m_8.element().key()] != 0);
+ DLIB_TEST( *table_4b[m_8.element().key()] == m_8.element().value());
+ }
+
+ while (table_4b.move_next())
+ {
+ DLIB_TEST( m_8[table_4b.element().key()] != 0);
+ DLIB_TEST( *m_8[table_4b.element().key()] == table_4b.element().value());
+ }
+
+ }
+
+
+
+
+
+ class static_map_tester : public tester
+ {
+ public:
+ static_map_tester (
+ ) :
+ tester ("test_static_map",
+ "Runs tests on the static_map component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ static_map_kernel_test<static_map<int,int>::kernel_1a> ();
+ dlog << LINFO << "testing kernel_1a_c";
+ static_map_kernel_test<static_map<int,int>::kernel_1a_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/static_set.cpp b/ml/dlib/dlib/test/static_set.cpp
new file mode 100644
index 000000000..0ad864e4a
--- /dev/null
+++ b/ml/dlib/dlib/test/static_set.cpp
@@ -0,0 +1,206 @@
+// Copyright (C) 2005 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/queue.h>
+#include <dlib/static_set.h>
+#include <dlib/set.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.static_set");
+
+ template <
+ typename set
+ >
+ void static_set_kernel_test (
+ )
+ /*!
+ requires
+ - set is an implementation of static_set/static_set_kernel_abstract.h and
+ is instantiated to hold ints
+ ensures
+ - runs tests on set for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ srand(static_cast<unsigned int>(time(0)));
+
+ typedef queue<int>::kernel_2a_c queue_of_int;
+ typedef dlib::set<int>::kernel_1a_c set_of_int;
+
+ queue_of_int q, qb, qc;
+ set_of_int ds;
+
+ set S;
+ S.load(ds);
+
+ for (int k = 1; k < 1000; ++k)
+ {
+ q.clear();
+ qb.clear();
+ qc.clear();
+ unsigned long num = k;
+ for (unsigned long i = 0; i < num; ++i)
+ {
+ int a = ::rand()&0xFF;
+ int b = a;
+ int c = a;
+ q.enqueue(a);
+ qb.enqueue(b);
+ qc.enqueue(c);
+ }
+
+
+
+ set s;
+
+ DLIB_TEST(s.size() == 0);
+ DLIB_TEST(s.at_start());
+ DLIB_TEST(s.current_element_valid() == false);
+ DLIB_TEST(s.move_next() == false);
+ DLIB_TEST(s.current_element_valid() == false);
+ DLIB_TEST(s.at_start() == false);
+
+ s.load(q);
+ DLIB_TEST(s.at_start());
+ set se;
+ se.load(q);
+
+ DLIB_TEST(se.size() == 0);
+ DLIB_TEST(se.at_start() == true);
+ DLIB_TEST(se.current_element_valid() == false);
+ DLIB_TEST(se.move_next() == false);
+ DLIB_TEST(se.at_start() == false);
+ DLIB_TEST(se.current_element_valid() == false);
+
+
+ DLIB_TEST(s.size() == qb.size());
+ DLIB_TEST(s.at_start() == true);
+ DLIB_TEST(s.current_element_valid() == false);
+ DLIB_TEST(s.move_next() == true);
+ DLIB_TEST(s.at_start() == false);
+ DLIB_TEST(s.current_element_valid() == true);
+ s.reset();
+ se.reset();
+
+ swap(se,s);
+
+ DLIB_TEST(s.size() == 0);
+ DLIB_TEST(s.at_start() == true);
+ DLIB_TEST(s.current_element_valid() == false);
+ DLIB_TEST(s.move_next() == false);
+ DLIB_TEST(s.at_start() == false);
+ DLIB_TEST(s.current_element_valid() == false);
+
+ DLIB_TEST(se.size() == qb.size());
+ DLIB_TEST(se.at_start() == true);
+ DLIB_TEST(se.current_element_valid() == false);
+ DLIB_TEST(se.move_next() == true);
+ DLIB_TEST(se.at_start() == false);
+ DLIB_TEST(se.current_element_valid() == true);
+ s.reset();
+ se.reset();
+
+ swap(se,s);
+
+
+
+ int last = 0;
+ while (s.move_next())
+ {
+ DLIB_TEST(last <= s.element());
+ last = s.element();
+ }
+
+
+
+ while (qb.move_next())
+ {
+ int a;
+ qb.dequeue(a);
+ DLIB_TEST(s.is_member(a));
+ DLIB_TEST(!se.is_member(a));
+
+ // make sure is_member() doesn't hang
+ for (int l = 0; l < 100; ++l)
+ {
+ int a = ::rand();
+ s.is_member(a);
+ }
+ }
+
+ swap(s,se);
+
+ // serialize the state of se, then clear se, then
+ // load the state back into se.
+ ostringstream sout;
+ serialize(se,sout);
+ DLIB_TEST(se.at_start() == true);
+ istringstream sin(sout.str());
+ se.clear();
+ deserialize(se,sin);
+ DLIB_TEST(se.at_start() == true);
+
+
+ last = 0;
+ while (se.move_next())
+ {
+ DLIB_TEST(last <= se.element());
+ last = se.element();
+ }
+
+
+ DLIB_TEST(s.size() == 0);
+ DLIB_TEST(se.size() == qc.size());
+
+ while (qc.move_next())
+ {
+ int a;
+ qc.dequeue(a);
+ DLIB_TEST(se.is_member(a));
+ DLIB_TEST(!s.is_member(a));
+ }
+
+
+ }
+ }
+
+
+
+
+
+ class static_set_tester : public tester
+ {
+ public:
+ static_set_tester (
+ ) :
+ tester ("test_static_set",
+ "Runs tests on the static_set component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ static_set_kernel_test<static_set<int>::kernel_1a> ();
+ dlog << LINFO << "testing kernel_1a_c";
+ static_set_kernel_test<static_set<int>::kernel_1a_c>();
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/statistics.cpp b/ml/dlib/dlib/test/statistics.cpp
new file mode 100644
index 000000000..0394286ad
--- /dev/null
+++ b/ml/dlib/dlib/test/statistics.cpp
@@ -0,0 +1,915 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/statistics.h>
+#include <dlib/rand.h>
+#include <dlib/svm.h>
+#include <algorithm>
+#include <dlib/matrix.h>
+#include <cmath>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.statistics");
+
+
+
+ class statistics_tester : public tester
+ {
+ public:
+ statistics_tester (
+ ) :
+ tester ("test_statistics",
+ "Runs tests on the statistics component.")
+ {}
+
+ void test_random_subset_selector ()
+ {
+ random_subset_selector<double> rand_set;
+
+ for (int j = 0; j < 30; ++j)
+ {
+ print_spinner();
+
+ running_stats<double> rs, rs2;
+
+ rand_set.set_max_size(1000);
+
+ for (double i = 0; i < 100000; ++i)
+ {
+ rs.add(i);
+ rand_set.add(i);
+ }
+
+
+ for (unsigned long i = 0; i < rand_set.size(); ++i)
+ rs2.add(rand_set[i]);
+
+
+ dlog << LDEBUG << "true mean: " << rs.mean();
+ dlog << LDEBUG << "true sampled: " << rs2.mean();
+ double ratio = rs.mean()/rs2.mean();
+ DLIB_TEST_MSG(0.96 < ratio && ratio < 1.04, " ratio: " << ratio);
+ }
+
+
+ {
+ random_subset_selector<int> r1, r2;
+ r1.set_max_size(300);
+ for (int i = 0; i < 4000; ++i)
+ r1.add(i);
+
+ ostringstream sout;
+ serialize(r1, sout);
+ istringstream sin(sout.str());
+ deserialize(r2, sin);
+
+ DLIB_TEST(r1.size() == r2.size());
+ DLIB_TEST(r1.max_size() == r2.max_size());
+ DLIB_TEST(r1.next_add_accepts() == r2.next_add_accepts());
+ DLIB_TEST(std::equal(r1.begin(), r1.end(), r2.begin()));
+
+ for (int i = 0; i < 4000; ++i)
+ {
+ r1.add(i);
+ r2.add(i);
+ }
+
+ DLIB_TEST(r1.size() == r2.size());
+ DLIB_TEST(r1.max_size() == r2.max_size());
+ DLIB_TEST(r1.next_add_accepts() == r2.next_add_accepts());
+ DLIB_TEST(std::equal(r1.begin(), r1.end(), r2.begin()));
+ }
+ }
+
+ void test_random_subset_selector2 ()
+ {
+ random_subset_selector<double> rand_set;
+ DLIB_TEST(rand_set.next_add_accepts() == false);
+ DLIB_TEST(rand_set.size() == 0);
+ DLIB_TEST(rand_set.max_size() == 0);
+
+ for (int j = 0; j < 30; ++j)
+ {
+ print_spinner();
+
+ running_stats<double> rs, rs2;
+
+ rand_set.set_max_size(1000);
+ DLIB_TEST(rand_set.next_add_accepts() == true);
+
+ for (double i = 0; i < 100000; ++i)
+ {
+ rs.add(i);
+ if (rand_set.next_add_accepts())
+ rand_set.add(i);
+ else
+ rand_set.add();
+ }
+
+ DLIB_TEST(rand_set.size() == 1000);
+ DLIB_TEST(rand_set.max_size() == 1000);
+
+ for (unsigned long i = 0; i < rand_set.size(); ++i)
+ rs2.add(rand_set[i]);
+
+
+ dlog << LDEBUG << "true mean: " << rs.mean();
+ dlog << LDEBUG << "true sampled: " << rs2.mean();
+ double ratio = rs.mean()/rs2.mean();
+ DLIB_TEST_MSG(0.96 < ratio && ratio < 1.04, " ratio: " << ratio);
+ }
+ }
+
+ void test_running_cross_covariance ()
+ {
+ running_cross_covariance<matrix<double> > rcc1, rcc2;
+
+ matrix<double,0,1> xm, ym;
+ const int num = 40;
+
+ dlib::rand rnd;
+ for (int i = 0; i < num; ++i)
+ {
+ matrix<double,0,1> x = randm(4,1,rnd);
+ matrix<double,0,1> y = randm(4,1,rnd);
+
+ xm += x/num;
+ ym += y/num;
+
+ if (i < 15)
+ rcc1.add(x,y);
+ else
+ rcc2.add(x,y);
+ }
+
+ rnd.clear();
+ matrix<double> cov;
+ for (int i = 0; i < num; ++i)
+ {
+ matrix<double,0,1> x = randm(4,1,rnd);
+ matrix<double,0,1> y = randm(4,1,rnd);
+ cov += (x-xm)*trans(y-ym);
+ }
+ cov /= num-1;
+
+ running_cross_covariance<matrix<double> > rcc = rcc1 + rcc2;
+ DLIB_TEST(max(abs(rcc.covariance_xy()-cov)) < 1e-14);
+ DLIB_TEST(max(abs(rcc.mean_x()-xm)) < 1e-14);
+ DLIB_TEST(max(abs(rcc.mean_y()-ym)) < 1e-14);
+ }
+
+ std::map<unsigned long,double> dense_to_sparse (
+ const matrix<double,0,1>& x
+ )
+ {
+ std::map<unsigned long,double> temp;
+ for (long i = 0; i < x.size(); ++i)
+ temp[i] = x(i);
+ return temp;
+ }
+
+ void test_running_cross_covariance_sparse()
+ {
+ running_cross_covariance<matrix<double> > rcc1, rcc2;
+
+ running_covariance<matrix<double> > rc1, rc2;
+
+ matrix<double,0,1> xm, ym;
+ const int num = 40;
+
+ rc1.set_dimension(4);
+ rc2.set_dimension(4);
+
+ rcc1.set_dimensions(4,5);
+ rcc2.set_dimensions(4,5);
+
+ dlib::rand rnd;
+ for (int i = 0; i < num; ++i)
+ {
+ matrix<double,0,1> x = randm(4,1,rnd);
+ matrix<double,0,1> y = randm(5,1,rnd);
+
+ xm += x/num;
+ ym += y/num;
+
+ if (i < 15)
+ {
+ rcc1.add(x,dense_to_sparse(y));
+ rc1.add(x);
+ }
+ else if (i < 30)
+ {
+ rcc2.add(dense_to_sparse(x),y);
+ rc2.add(dense_to_sparse(x));
+ }
+ else
+ {
+ rcc2.add(dense_to_sparse(x),dense_to_sparse(y));
+ rc2.add(x);
+ }
+ }
+
+ rnd.clear();
+ matrix<double> cov, cov2;
+ for (int i = 0; i < num; ++i)
+ {
+ matrix<double,0,1> x = randm(4,1,rnd);
+ matrix<double,0,1> y = randm(5,1,rnd);
+ cov += (x-xm)*trans(y-ym);
+ cov2 += (x-xm)*trans(x-xm);
+ }
+ cov /= num-1;
+ cov2 /= num-1;
+
+ running_cross_covariance<matrix<double> > rcc = rcc1 + rcc2;
+ DLIB_TEST_MSG(max(abs(rcc.covariance_xy()-cov)) < 1e-14, max(abs(rcc.covariance_xy()-cov)));
+ DLIB_TEST(max(abs(rcc.mean_x()-xm)) < 1e-14);
+ DLIB_TEST(max(abs(rcc.mean_y()-ym)) < 1e-14);
+
+ running_covariance<matrix<double> > rc = rc1 + rc2;
+ DLIB_TEST(max(abs(rc.covariance()-cov2)) < 1e-14);
+ DLIB_TEST(max(abs(rc.mean()-xm)) < 1e-14);
+ }
+
+ void test_running_covariance (
+ )
+ {
+ dlib::rand rnd;
+ std::vector<matrix<double,0,1> > vects;
+
+ running_covariance<matrix<double,0,1> > cov, cov2;
+ DLIB_TEST(cov.in_vector_size() == 0);
+
+ for (unsigned long dims = 1; dims < 5; ++dims)
+ {
+ for (unsigned long samps = 2; samps < 10; ++samps)
+ {
+ vects.clear();
+ cov.clear();
+ DLIB_TEST(cov.in_vector_size() == 0);
+ for (unsigned long i = 0; i < samps; ++i)
+ {
+ vects.push_back(randm(dims,1,rnd));
+ cov.add(vects.back());
+
+ }
+ DLIB_TEST(cov.in_vector_size() == (long)dims);
+
+ DLIB_TEST(equal(mean(mat(vects)), cov.mean()));
+ DLIB_TEST_MSG(equal(covariance(mat(vects)), cov.covariance()),
+ max(abs(covariance(mat(vects)) - cov.covariance()))
+ << " dims = " << dims << " samps = " << samps
+ );
+ }
+ }
+
+ for (unsigned long dims = 1; dims < 5; ++dims)
+ {
+ for (unsigned long samps = 2; samps < 10; ++samps)
+ {
+ vects.clear();
+ cov.clear();
+ cov2.clear();
+ DLIB_TEST(cov.in_vector_size() == 0);
+ for (unsigned long i = 0; i < samps; ++i)
+ {
+ vects.push_back(randm(dims,1,rnd));
+ if ((i%2) == 0)
+ cov.add(vects.back());
+ else
+ cov2.add(vects.back());
+
+ }
+ DLIB_TEST((cov+cov2).in_vector_size() == (long)dims);
+
+ DLIB_TEST(equal(mean(mat(vects)), (cov+cov2).mean()));
+ DLIB_TEST_MSG(equal(covariance(mat(vects)), (cov+cov2).covariance()),
+ max(abs(covariance(mat(vects)) - (cov+cov2).covariance()))
+ << " dims = " << dims << " samps = " << samps
+ );
+ }
+ }
+
+ }
+
+ void test_running_stats()
+ {
+ print_spinner();
+
+ running_stats<double> rs, rs2;
+
+ running_scalar_covariance<double> rsc1, rsc2;
+ running_scalar_covariance_decayed<double> rscd1(1000000), rscd2(1000000);
+
+ for (double i = 0; i < 100; ++i)
+ {
+ rs.add(i);
+
+ rsc1.add(i,i);
+ rsc2.add(i,i);
+ rsc2.add(i,-i);
+
+ rscd1.add(i,i);
+ rscd2.add(i,i);
+ rscd2.add(i,-i);
+ }
+
+ // make sure the running_stats and running_scalar_covariance agree
+ DLIB_TEST_MSG(std::abs(rs.mean() - rsc1.mean_x()) < 1e-10, std::abs(rs.mean() - rsc1.mean_x()));
+ DLIB_TEST(std::abs(rs.mean() - rsc1.mean_y()) < 1e-10);
+ DLIB_TEST(std::abs(rs.stddev() - rsc1.stddev_x()) < 1e-10);
+ DLIB_TEST(std::abs(rs.stddev() - rsc1.stddev_y()) < 1e-10);
+ DLIB_TEST(std::abs(rs.variance() - rsc1.variance_x()) < 1e-10);
+ DLIB_TEST(std::abs(rs.variance() - rsc1.variance_y()) < 1e-10);
+ DLIB_TEST(rs.current_n() == rsc1.current_n());
+
+ DLIB_TEST(std::abs(rsc1.correlation() - 1) < 1e-10);
+ DLIB_TEST(std::abs(rsc2.correlation() - 0) < 1e-10);
+
+
+ DLIB_TEST_MSG(std::abs(rs.mean() - rscd1.mean_x()) < 1e-2, std::abs(rs.mean() - rscd1.mean_x()) << " " << rscd1.mean_x());
+ DLIB_TEST(std::abs(rs.mean() - rscd1.mean_y()) < 1e-2);
+ DLIB_TEST_MSG(std::abs(rs.stddev() - rscd1.stddev_x()) < 1e-2, std::abs(rs.stddev() - rscd1.stddev_x()));
+ DLIB_TEST(std::abs(rs.stddev() - rscd1.stddev_y()) < 1e-2);
+ DLIB_TEST_MSG(std::abs(rs.variance() - rscd1.variance_x()) < 1e-2, std::abs(rs.variance() - rscd1.variance_x()));
+ DLIB_TEST(std::abs(rs.variance() - rscd1.variance_y()) < 1e-2);
+ DLIB_TEST(std::abs(rscd1.correlation() - 1) < 1e-2);
+ DLIB_TEST(std::abs(rscd2.correlation() - 0) < 1e-2);
+
+
+
+ // test serialization of running_stats
+ ostringstream sout;
+ serialize(rs, sout);
+ istringstream sin(sout.str());
+ deserialize(rs2, sin);
+ // make sure the running_stats and running_scalar_covariance agree
+ DLIB_TEST_MSG(std::abs(rs2.mean() - rsc1.mean_x()) < 1e-10, std::abs(rs2.mean() - rsc1.mean_x()));
+ DLIB_TEST(std::abs(rs2.mean() - rsc1.mean_y()) < 1e-10);
+ DLIB_TEST(std::abs(rs2.stddev() - rsc1.stddev_x()) < 1e-10);
+ DLIB_TEST(std::abs(rs2.stddev() - rsc1.stddev_y()) < 1e-10);
+ DLIB_TEST(std::abs(rs2.variance() - rsc1.variance_x()) < 1e-10);
+ DLIB_TEST(std::abs(rs2.variance() - rsc1.variance_y()) < 1e-10);
+ DLIB_TEST(rs2.current_n() == rsc1.current_n());
+
+ rsc1.clear();
+ rsc1.add(1, -1);
+ rsc1.add(0, 0);
+ rsc1.add(1, -1);
+ rsc1.add(0, 0);
+ rsc1.add(1, -1);
+ rsc1.add(0, 0);
+
+ DLIB_TEST(std::abs(rsc1.covariance() - -0.3) < 1e-10);
+ }
+
+ void test_skewness_and_kurtosis_1()
+ {
+
+ dlib::rand rnum;
+ running_stats<double> rs1;
+
+ double tp = 0;
+
+ rnum.set_seed("DlibRocks");
+
+ for(int i = 0; i< 1000000; i++)
+ {
+ tp = rnum.get_random_gaussian();
+ rs1.add(tp);
+ }
+
+ // check the unbiased skewness and excess kurtosis of one million Gaussian
+ // draws are both near_vects zero.
+ DLIB_TEST(abs(rs1.skewness()) < 0.1);
+ DLIB_TEST(abs(rs1.ex_kurtosis()) < 0.1);
+ }
+
+ void test_skewness_and_kurtosis_2()
+ {
+
+ string str = "DlibRocks";
+
+ for(int j = 0; j<5 ; j++)
+ {
+ matrix<double,1,100000> dat;
+ dlib::rand rnum;
+ running_stats<double> rs1;
+
+ double tp = 0;
+ double n = 100000;
+ double xb = 0;
+
+ double sknum = 0;
+ double skdenom = 0;
+ double unbi_skew = 0;
+
+ double exkurnum = 0;
+ double exkurdenom = 0;
+ double unbi_exkur = 0;
+
+ random_shuffle(str.begin(), str.end());
+ rnum.set_seed(str);
+
+ for(int i = 0; i<n; i++)
+ {
+ tp = rnum.get_random_gaussian();
+ rs1.add(tp);
+ dat(i)=tp;
+ xb += dat(i);
+ }
+
+ xb = xb/n;
+
+ for(int i = 0; i < n; i++ )
+ {
+ sknum += pow(dat(i) - xb,3);
+ skdenom += pow(dat(i) - xb,2);
+ exkurnum += pow(dat(i) - xb,4);
+ exkurdenom += pow(dat(i)-xb,2);
+ }
+
+ sknum = sknum/n;
+ skdenom = pow(skdenom/n,1.5);
+ exkurnum = exkurnum/n;
+ exkurdenom = pow(exkurdenom/n,2);
+
+ unbi_skew = sqrt(n*(n-1))/(n-2)*sknum/skdenom;
+ unbi_exkur = (n-1)*((n+1)*(exkurnum/exkurdenom-3)+6)/((n-2)*(n-3));
+
+ dlog << LINFO << "Skew Diff: " << unbi_skew - rs1.skewness();
+ dlog << LINFO << "Kur Diff: " << unbi_exkur - rs1.ex_kurtosis();
+
+ // Test an alternative implementation of the unbiased skewness and excess
+ // kurtosis against the one in running_stats.
+ DLIB_TEST(abs(unbi_skew - rs1.skewness()) < 1e-10);
+ DLIB_TEST(abs(unbi_exkur - rs1.ex_kurtosis()) < 1e-10);
+ }
+ }
+
+ void test_randomize_samples()
+ {
+ std::vector<unsigned int> t(15),u(15),v(15);
+
+ for (unsigned long i = 0; i < t.size(); ++i)
+ {
+ t[i] = i;
+ u[i] = i+1;
+ v[i] = i+2;
+ }
+ randomize_samples(t,u,v);
+
+ DLIB_TEST(t.size() == 15);
+ DLIB_TEST(u.size() == 15);
+ DLIB_TEST(v.size() == 15);
+
+ for (unsigned long i = 0; i < t.size(); ++i)
+ {
+ const unsigned long val = t[i];
+ DLIB_TEST(u[i] == val+1);
+ DLIB_TEST(v[i] == val+2);
+ }
+ }
+ void test_randomize_samples2()
+ {
+ dlib::matrix<int,15,1> t(15),u(15),v(15);
+
+ for (long i = 0; i < t.size(); ++i)
+ {
+ t(i) = i;
+ u(i) = i+1;
+ v(i) = i+2;
+ }
+ randomize_samples(t,u,v);
+
+ DLIB_TEST(t.size() == 15);
+ DLIB_TEST(u.size() == 15);
+ DLIB_TEST(v.size() == 15);
+
+ for (long i = 0; i < t.size(); ++i)
+ {
+ const long val = t(i);
+ DLIB_TEST(u(i) == val+1);
+ DLIB_TEST(v(i) == val+2);
+ }
+ }
+
+ void another_test()
+ {
+ std::vector<double> a;
+
+ running_stats<double> rs1, rs2;
+
+ for (int i = 0; i < 10; ++i)
+ {
+ rs1.add(i);
+ a.push_back(i);
+ }
+
+ DLIB_TEST(std::abs(variance(mat(a)) - rs1.variance()) < 1e-13);
+ DLIB_TEST(std::abs(stddev(mat(a)) - rs1.stddev()) < 1e-13);
+ DLIB_TEST(std::abs(mean(mat(a)) - rs1.mean()) < 1e-13);
+
+ for (int i = 10; i < 20; ++i)
+ {
+ rs2.add(i);
+ a.push_back(i);
+ }
+
+ DLIB_TEST(std::abs(variance(mat(a)) - (rs1+rs2).variance()) < 1e-13);
+ DLIB_TEST(std::abs(mean(mat(a)) - (rs1+rs2).mean()) < 1e-13);
+ DLIB_TEST((rs1+rs2).current_n() == 20);
+
+ running_scalar_covariance<double> rc1, rc2, rc3;
+ dlib::rand rnd;
+ for (double i = 0; i < 10; ++i)
+ {
+ const double a = i + rnd.get_random_gaussian();
+ const double b = i + rnd.get_random_gaussian();
+ rc1.add(a,b);
+ rc3.add(a,b);
+ }
+ for (double i = 11; i < 20; ++i)
+ {
+ const double a = i + rnd.get_random_gaussian();
+ const double b = i + rnd.get_random_gaussian();
+ rc2.add(a,b);
+ rc3.add(a,b);
+ }
+
+ DLIB_TEST(std::abs((rc1+rc2).mean_x() - rc3.mean_x()) < 1e-13);
+ DLIB_TEST(std::abs((rc1+rc2).mean_y() - rc3.mean_y()) < 1e-13);
+ DLIB_TEST_MSG(std::abs((rc1+rc2).variance_x() - rc3.variance_x()) < 1e-13, std::abs((rc1+rc2).variance_x() - rc3.variance_x()));
+ DLIB_TEST(std::abs((rc1+rc2).variance_y() - rc3.variance_y()) < 1e-13);
+ DLIB_TEST(std::abs((rc1+rc2).covariance() - rc3.covariance()) < 1e-13);
+ DLIB_TEST((rc1+rc2).current_n() == rc3.current_n());
+
+ }
+
+ void test_average_precision()
+ {
+ std::vector<bool> items;
+ DLIB_TEST(average_precision(items) == 1);
+ DLIB_TEST(average_precision(items,1) == 0);
+
+ items.push_back(true);
+ DLIB_TEST(average_precision(items) == 1);
+ DLIB_TEST(std::abs(average_precision(items,1) - 0.5) < 1e-14);
+
+ items.push_back(true);
+ DLIB_TEST(average_precision(items) == 1);
+ DLIB_TEST(std::abs(average_precision(items,1) - 2.0/3.0) < 1e-14);
+
+ items.push_back(false);
+
+ DLIB_TEST(average_precision(items) == 1);
+ DLIB_TEST(std::abs(average_precision(items,1) - 2.0/3.0) < 1e-14);
+
+ items.push_back(true);
+
+ DLIB_TEST(std::abs(average_precision(items) - (2.0+3.0/4.0)/3.0) < 1e-14);
+
+ items.push_back(true);
+
+ DLIB_TEST(std::abs(average_precision(items) - (2.0 + 4.0/5.0 + 4.0/5.0)/4.0) < 1e-14);
+ DLIB_TEST(std::abs(average_precision(items,1) - (2.0 + 4.0/5.0 + 4.0/5.0)/5.0) < 1e-14);
+ }
+
+
+ template <typename sample_type>
+ void check_distance_metrics (
+ const std::vector<frobmetric_training_sample<sample_type> >& samples
+ )
+ {
+ running_stats<double> rs;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ for (unsigned long j = 0; j < samples[i].near_vects.size(); ++j)
+ {
+ const double d1 = length_squared(samples[i].anchor_vect - samples[i].near_vects[j]);
+ for (unsigned long k = 0; k < samples[i].far_vects.size(); ++k)
+ {
+ const double d2 = length_squared(samples[i].anchor_vect - samples[i].far_vects[k]);
+ rs.add(d2-d1);
+ }
+ }
+ }
+
+ dlog << LINFO << "dist gap max: "<< rs.max();
+ dlog << LINFO << "dist gap min: "<< rs.min();
+ dlog << LINFO << "dist gap mean: "<< rs.mean();
+ dlog << LINFO << "dist gap stddev: "<< rs.stddev();
+ DLIB_TEST(rs.min() >= 0.99);
+ DLIB_TEST(rs.mean() >= 0.9999);
+ }
+
+ void test_vector_normalizer_frobmetric(dlib::rand& rnd)
+ {
+ print_spinner();
+ typedef matrix<double,0,1> sample_type;
+ vector_normalizer_frobmetric<sample_type> normalizer;
+
+ std::vector<frobmetric_training_sample<sample_type> > samples;
+ frobmetric_training_sample<sample_type> samp;
+
+ const long key = 1;
+ const long dims = 5;
+ // Lets make some two class training data. Each sample will have dims dimensions but
+ // only the one with index equal to key will be meaningful. In particular, if the key
+ // dimension is > 0 then the sample is class +1 and -1 otherwise.
+
+ long k = 0;
+ for (int i = 0; i < 50; ++i)
+ {
+ samp.clear();
+ samp.anchor_vect = gaussian_randm(dims,1,k++);
+ if (samp.anchor_vect(key) > 0)
+ samp.anchor_vect(key) = rnd.get_random_double() + 5;
+ else
+ samp.anchor_vect(key) = -(rnd.get_random_double() + 5);
+
+ matrix<double,0,1> temp;
+
+ for (int j = 0; j < 5; ++j)
+ {
+ // Don't always put an equal number of near_vects and far_vects vectors into the
+ // training samples.
+ const int numa = rnd.get_random_32bit_number()%2 + 1;
+ const int numb = rnd.get_random_32bit_number()%2 + 1;
+
+ for (int num = 0; num < numa; ++num)
+ {
+ temp = gaussian_randm(dims,1,k++); temp(key) = 0.1;
+ //temp = gaussian_randm(dims,1,k++); temp(key) = std::abs(temp(key));
+ if (samp.anchor_vect(key) > 0) samp.near_vects.push_back(temp);
+ else samp.far_vects.push_back(temp);
+ }
+
+ for (int num = 0; num < numb; ++num)
+ {
+ temp = gaussian_randm(dims,1,k++); temp(key) = -0.1;
+ //temp = gaussian_randm(dims,1,k++); temp(key) = -std::abs(temp(key));
+ if (samp.anchor_vect(key) < 0) samp.near_vects.push_back(temp);
+ else samp.far_vects.push_back(temp);
+ }
+ }
+ samples.push_back(samp);
+ }
+
+ normalizer.set_epsilon(0.0001);
+ normalizer.set_c(100);
+ normalizer.set_max_iterations(6000);
+ normalizer.train(samples);
+
+ dlog << LINFO << "learned transform: \n" << normalizer.transform();
+
+ matrix<double,0,1> total;
+
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ samples[i].anchor_vect = normalizer(samples[i].anchor_vect);
+ total += samples[i].anchor_vect;
+ for (unsigned long j = 0; j < samples[i].near_vects.size(); ++j)
+ samples[i].near_vects[j] = normalizer(samples[i].near_vects[j]);
+ for (unsigned long j = 0; j < samples[i].far_vects.size(); ++j)
+ samples[i].far_vects[j] = normalizer(samples[i].far_vects[j]);
+ }
+ total /= samples.size();
+ dlog << LINFO << "sample transformed means: "<< trans(total);
+ DLIB_TEST(length(total) < 1e-9);
+ check_distance_metrics(samples);
+
+ // make sure serialization works
+ stringstream os;
+ serialize(normalizer, os);
+ vector_normalizer_frobmetric<sample_type> normalizer2;
+ deserialize(normalizer2, os);
+ DLIB_TEST(equal(normalizer.transform(), normalizer2.transform()));
+ DLIB_TEST(equal(normalizer.transformed_means(), normalizer2.transformed_means()));
+ DLIB_TEST(normalizer.in_vector_size() == normalizer2.in_vector_size());
+ DLIB_TEST(normalizer.out_vector_size() == normalizer2.out_vector_size());
+ DLIB_TEST(normalizer.get_max_iterations() == normalizer2.get_max_iterations());
+ DLIB_TEST(std::abs(normalizer.get_c() - normalizer2.get_c()) < 1e-14);
+ DLIB_TEST(std::abs(normalizer.get_epsilon() - normalizer2.get_epsilon()) < 1e-14);
+
+ }
+
+ void prior_frobnorm_test()
+ {
+ frobmetric_training_sample<matrix<double,0,1> > sample;
+ std::vector<frobmetric_training_sample<matrix<double,0,1> > > samples;
+
+ matrix<double,3,1> x, near_, far_;
+ x = 0,0,0;
+ near_ = 1,0,0;
+ far_ = 0,1,0;
+
+ sample.anchor_vect = x;
+ sample.near_vects.push_back(near_);
+ sample.far_vects.push_back(far_);
+
+ samples.push_back(sample);
+
+ vector_normalizer_frobmetric<matrix<double,0,1> > trainer;
+ trainer.set_c(100);
+ print_spinner();
+ trainer.train(samples);
+
+ matrix<double,3,3> correct;
+ correct = 0, 0, 0,
+ 0, 1, 0,
+ 0, 0, 0;
+
+ dlog << LDEBUG << trainer.transform();
+ DLIB_TEST(max(abs(trainer.transform()-correct)) < 1e-8);
+
+ trainer.set_uses_identity_matrix_prior(true);
+ print_spinner();
+ trainer.train(samples);
+ correct = 1, 0, 0,
+ 0, 2, 0,
+ 0, 0, 1;
+
+ dlog << LDEBUG << trainer.transform();
+ DLIB_TEST(max(abs(trainer.transform()-correct)) < 1e-8);
+
+ }
+
+ void test_lda ()
+ {
+ // This test makes sure we pick the right direction in a simple 2D -> 1D LDA
+ typedef matrix<double,2,1> sample_type;
+
+ std::vector<unsigned long> labels;
+ std::vector<sample_type> samples;
+ for (int i=0; i<4; i++)
+ {
+ sample_type s;
+ s(0) = i;
+ s(1) = i+1;
+ samples.push_back(s);
+ labels.push_back(1);
+
+ sample_type s1;
+ s1(0) = i+1;
+ s1(1) = i;
+ samples.push_back(s1);
+ labels.push_back(2);
+ }
+
+ matrix<double> X;
+ X.set_size(8,2);
+ for (int i=0; i<8; i++){
+ X(i,0) = samples[i](0);
+ X(i,1) = samples[i](1);
+ }
+
+ matrix<double,0,1> mean;
+
+ dlib::compute_lda_transform(X,mean,labels,1);
+
+ std::vector<double> vals1, vals2;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ double val = X*samples[i]-mean;
+ if (i%2 == 0)
+ vals1.push_back(val);
+ else
+ vals2.push_back(val);
+ dlog << LINFO << "1D LDA output: " << val;
+ }
+
+ if (vals1[0] > vals2[0])
+ swap(vals1, vals2);
+
+ const double err = equal_error_rate(vals1, vals2).first;
+ dlog << LINFO << "LDA ERR: " << err;
+ DLIB_TEST(err == 0);
+ DLIB_TEST(equal_error_rate(vals2, vals1).first == 1);
+ }
+
+ void test_running_stats_decayed()
+ {
+ print_spinner();
+ std::vector<double> tmp(300);
+ std::vector<double> tmp_var(tmp.size());
+ dlib::rand rnd;
+ const int num_rounds = 100000;
+ for (int rounds = 0; rounds < num_rounds; ++rounds)
+ {
+ running_stats_decayed<double> rs(100);
+
+ for (size_t i = 0; i < tmp.size(); ++i)
+ {
+ rs.add(rnd.get_random_gaussian() + 1);
+ tmp[i] += rs.mean();
+ if (i > 0)
+ tmp_var[i] += rs.variance();
+ }
+ }
+
+ // should print all 1s basically since the mean and variance should always be 1.
+ for (size_t i = 0; i < tmp.size(); ++i)
+ {
+ DLIB_TEST(std::abs(1-tmp[i]/num_rounds) < 0.001);
+ if (i > 1)
+ DLIB_TEST(std::abs(1-tmp_var[i]/num_rounds) < 0.01);
+ }
+ }
+
+ void test_running_scalar_covariance_decayed()
+ {
+ print_spinner();
+ std::vector<double> tmp(300);
+ std::vector<double> tmp_var(tmp.size());
+ std::vector<double> tmp_covar(tmp.size());
+ dlib::rand rnd;
+ const int num_rounds = 500000;
+ for (int rounds = 0; rounds < num_rounds; ++rounds)
+ {
+ running_scalar_covariance_decayed<double> rs(100);
+
+ for (size_t i = 0; i < tmp.size(); ++i)
+ {
+ rs.add(rnd.get_random_gaussian() + 1, rnd.get_random_gaussian() + 1);
+ tmp[i] += (rs.mean_y()+rs.mean_x())/2;
+ if (i > 0)
+ {
+ tmp_var[i] += (rs.variance_y()+rs.variance_x())/2;
+ tmp_covar[i] += rs.covariance();
+ }
+ }
+ }
+
+ // should print all 1s basically since the mean and variance should always be 1.
+ for (size_t i = 0; i < tmp.size(); ++i)
+ {
+ DLIB_TEST(std::abs(1-tmp[i]/num_rounds) < 0.001);
+ if (i > 1)
+ {
+ DLIB_TEST(std::abs(1-tmp_var[i]/num_rounds) < 0.01);
+ DLIB_TEST(std::abs(tmp_covar[i]/num_rounds) < 0.001);
+ }
+ }
+ }
+
+
+ void test_event_corr()
+ {
+ print_spinner();
+ DLIB_TEST(event_correlation(1000,1000,500,2000) == 0);
+ DLIB_TEST(std::abs(event_correlation(1000,1000,300,2000) + 164.565757010104) < 1e-11);
+ DLIB_TEST(std::abs(event_correlation(1000,1000,700,2000) - 164.565757010104) < 1e-11);
+
+ DLIB_TEST(event_correlation(10,1000,5,2000) == 0);
+ DLIB_TEST(event_correlation(1000,10,5,2000) == 0);
+ DLIB_TEST(std::abs(event_correlation(10,1000,1,2000) - event_correlation(1000,10,1,2000)) < 1e-11);
+ DLIB_TEST(std::abs(event_correlation(10,1000,9,2000) - event_correlation(1000,10,9,2000)) < 1e-11);
+
+ DLIB_TEST(std::abs(event_correlation(10,1000,1,2000) + 3.69672251700842) < 1e-11);
+ DLIB_TEST(std::abs(event_correlation(10,1000,9,2000) - 3.69672251700842) < 1e-11);
+ }
+
+ void perform_test (
+ )
+ {
+ prior_frobnorm_test();
+ dlib::rand rnd;
+ for (int i = 0; i < 5; ++i)
+ test_vector_normalizer_frobmetric(rnd);
+
+ test_random_subset_selector();
+ test_random_subset_selector2();
+ test_running_covariance();
+ test_running_cross_covariance();
+ test_running_cross_covariance_sparse();
+ test_running_stats();
+ test_skewness_and_kurtosis_1();
+ test_skewness_and_kurtosis_2();
+ test_randomize_samples();
+ test_randomize_samples2();
+ another_test();
+ test_average_precision();
+ test_lda();
+ test_event_corr();
+ test_running_stats_decayed();
+ test_running_scalar_covariance_decayed();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/std_vector_c.cpp b/ml/dlib/dlib/test/std_vector_c.cpp
new file mode 100644
index 000000000..fe7f82514
--- /dev/null
+++ b/ml/dlib/dlib/test/std_vector_c.cpp
@@ -0,0 +1,101 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/stl_checked.h>
+
+#include "tester.h"
+
+// This is called an unnamed-namespace and it has the effect of making everything inside this file "private"
+// so that everything you declare will have static linkage. Thus we won't have any multiply
+// defined symbol errors coming out of the linker when we try to compile the test suite.
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ // Declare the logger we will use in this test. The name of the tester
+ // should start with "test."
+ logger dlog("test.std_vector_c");
+
+
+ class std_vector_c_tester : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a test for the std_vector_c object. When it is constructed
+ it adds itself into the testing framework. The command line switch is
+ specified as test_std_vector_c by passing that string to the tester constructor.
+ !*/
+ public:
+ std_vector_c_tester (
+ ) :
+ tester ("test_std_vector_c",
+ "Runs tests on the std_vector_c component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ std::vector<int> c;
+ std_vector_c<int> a, b;
+ a.push_back(3);
+ a.push_back(2);
+ a.push_back(1);
+
+ DLIB_TEST(a[0] == 3);
+ DLIB_TEST(a[1] == 2);
+ DLIB_TEST(a[2] == 1);
+ c = a;
+ DLIB_TEST(c[0] == 3);
+ DLIB_TEST(c[1] == 2);
+ DLIB_TEST(c[2] == 1);
+ DLIB_TEST(c.size() == 3);
+ DLIB_TEST(a.size() == 3);
+ DLIB_TEST(b.size() == 0);
+
+ DLIB_TEST(a == c);
+ DLIB_TEST(!(a != c));
+ DLIB_TEST(a <= c);
+ DLIB_TEST(a >= c);
+ DLIB_TEST(!(a < c));
+ DLIB_TEST(!(a > c));
+
+ swap(b,c);
+ DLIB_TEST(b[0] == 3);
+ DLIB_TEST(b[1] == 2);
+ DLIB_TEST(b[2] == 1);
+ DLIB_TEST(c.size() == 0);
+ DLIB_TEST(b.size() == 3);
+ swap(c,b);
+ DLIB_TEST(c[0] == 3);
+ DLIB_TEST(c[1] == 2);
+ DLIB_TEST(c[2] == 1);
+ DLIB_TEST(c.size() == 3);
+ DLIB_TEST(b.size() == 0);
+ swap(a,b);
+ DLIB_TEST(b[0] == 3);
+ DLIB_TEST(b[1] == 2);
+ DLIB_TEST(b[2] == 1);
+ DLIB_TEST(b.size() == 3);
+ DLIB_TEST(a.size() == 0);
+
+
+ swap(b,c);
+ swap(c,c);
+
+
+ std_vector_c<int> h(a);
+ std_vector_c<int> i(c);
+ std::vector<int> j(b);
+ }
+ } a;
+
+}
+
diff --git a/ml/dlib/dlib/test/string.cpp b/ml/dlib/dlib/test/string.cpp
new file mode 100644
index 000000000..18f9035c5
--- /dev/null
+++ b/ml/dlib/dlib/test/string.cpp
@@ -0,0 +1,329 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/string.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.string");
+
+
+ void string_test (
+ )
+ /*!
+ ensures
+ - runs tests on string functions for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ string a = " davis ";
+ string A = " DAVIS ";
+ string empty = " ";
+
+ dlog << LTRACE << 1;
+
+ double dval;
+ int ival;
+ bool bval;
+
+ DLIB_TEST_MSG(string_cast<int>("5") == 5,string_cast<int>("5"));
+ DLIB_TEST_MSG(string_cast<int>("0x5") == 5,string_cast<int>("0x5"));
+ DLIB_TEST_MSG(string_cast<int>("0xA") == 10,string_cast<int>("0xA"));
+ DLIB_TEST(string_cast<float>("0.5") == 0.5);
+ DLIB_TEST((dval = sa ="0.5") == 0.5);
+ DLIB_TEST(string_cast<std::string>("0.5 !") == "0.5 !");
+ DLIB_TEST(string_cast<bool>("true") == true);
+ DLIB_TEST((bval = sa = "true") == true);
+ DLIB_TEST(string_cast<bool>("false") == false);
+ DLIB_TEST(string_cast<bool>("TRUE") == true);
+ DLIB_TEST(string_cast<bool>("FALSE") == false);
+ DLIB_TEST((bval = sa = "FALSE") == false);
+
+ dlog << LTRACE << 2;
+
+ DLIB_TEST_MSG(string_cast<int>(L"5") == 5,string_cast<int>("5"));
+ DLIB_TEST_MSG((ival = sa = L"5") == 5,string_cast<int>("5"));
+ dlog << LTRACE << 2.1;
+ DLIB_TEST_MSG(string_cast<int>(L"0x5") == 5,string_cast<int>("0x5"));
+ DLIB_TEST_MSG(string_cast<int>(L"0xA") == 10,string_cast<int>("0xA"));
+ DLIB_TEST(string_cast<float>(L"0.5") == 0.5);
+ DLIB_TEST(string_cast<std::string>(L"0.5 !") == "0.5 !");
+ DLIB_TEST(string_cast<bool>(L"true") == true);
+ DLIB_TEST(string_cast<bool>(L"false") == false);
+ DLIB_TEST(string_cast<bool>(L"TRUE") == true);
+ DLIB_TEST((bval = sa = L"TRUE") == true);
+ DLIB_TEST(string_cast<bool>(L"FALSE") == false);
+
+ dlog << LTRACE << 3;
+
+ DLIB_TEST(cast_to_string(5) == "5");
+ DLIB_TEST(cast_to_string(5.5) == "5.5");
+
+ dlog << LTRACE << 4;
+ DLIB_TEST(cast_to_wstring(5) == L"5");
+ DLIB_TEST(cast_to_wstring(5.5) == L"5.5");
+ dlog << LTRACE << 5;
+ DLIB_TEST(toupper(a) == A);
+ DLIB_TEST(toupper(A) == A);
+ DLIB_TEST(tolower(a) == a);
+ DLIB_TEST(tolower(A) == a);
+ DLIB_TEST(trim(a) == "davis");
+ DLIB_TEST(ltrim(a) == "davis ");
+ DLIB_TEST(rtrim(a) == " davis");
+ DLIB_TEST(trim(string_cast<wstring>(a)) == L"davis");
+ DLIB_TEST(ltrim(string_cast<wstring>(a)) == L"davis ");
+ DLIB_TEST(rtrim(string_cast<wstring>(a)) == L" davis");
+ DLIB_TEST(trim(a, " ") == "davis");
+ DLIB_TEST(ltrim(a, " ") == "davis ");
+ DLIB_TEST(rtrim(a, " ") == " davis");
+ DLIB_TEST(trim(empty) == "");
+ DLIB_TEST(ltrim(empty) == "");
+ DLIB_TEST(rtrim(empty) == "");
+ DLIB_TEST(trim(string_cast<wstring>(empty)) == L"");
+ DLIB_TEST(ltrim(string_cast<wstring>(empty)) == L"");
+ DLIB_TEST(rtrim(string_cast<wstring>(empty)) == L"");
+ DLIB_TEST(trim(empty, " ") == "");
+ DLIB_TEST(ltrim(empty, " ") == "");
+ DLIB_TEST(rtrim(empty, " ") == "");
+
+
+ dlog << LTRACE << 6;
+ DLIB_TEST( (lpad(wstring(L"davis"), 10) == L" davis"));
+ DLIB_TEST( (rpad(wstring(L"davis"), 10) == L"davis "));
+ DLIB_TEST( (pad(wstring(L"davis"), 10) == L" davis "));
+
+ DLIB_TEST( (lpad(string("davis"), -10) == "davis"));
+ DLIB_TEST( (rpad(string("davis"), -10) == "davis"));
+ DLIB_TEST( (pad(string("davis"), -10) == "davis"));
+ DLIB_TEST( (lpad(string("davis"), 10) == " davis"));
+ DLIB_TEST( (rpad(string("davis"), 10) == "davis "));
+ DLIB_TEST( (pad(string("davis"), 10) == " davis "));
+ DLIB_TEST( (lpad(string("davis"), 10, string("*")) == "*****davis"));
+ DLIB_TEST( (rpad(string("davis"), 10, string("*")) == "davis*****"));
+ DLIB_TEST( (pad(string("davis"), 10, string("*")) == "**davis***"));
+ DLIB_TEST( (lpad(string("davis"), 10, string("_-")) == "_-_-_davis"));
+ DLIB_TEST( (rpad(string("davis"), 10, string("_-")) == "davis_-_-_"));
+ DLIB_TEST( (pad(string("davis"), 10, string("_-")) == "_-davis_-_"));
+ DLIB_TEST( (lpad(string("davis"), 10, string("willy wanka")) == "willydavis"));
+ DLIB_TEST( (rpad(string("davis"), 10, string("willy wanka")) == "daviswilly"));
+ DLIB_TEST( (pad(string("davis"), 10, string("willy wanka")) == "widaviswil"));
+ DLIB_TEST( (lpad(string("davis"), 10, "*")) == "*****davis");
+ DLIB_TEST( (rpad(string("davis"), 10, "*") == "davis*****"));
+ DLIB_TEST( (pad(string("davis"), 10, "*") == "**davis***"));
+ DLIB_TEST( (lpad(string("davis"), 10, "_-") == "_-_-_davis"));
+ DLIB_TEST( (rpad(string("davis"), 10, "_-") == "davis_-_-_"));
+ DLIB_TEST( (pad(string("davis"), 10, "_-") == "_-davis_-_"));
+ DLIB_TEST( (lpad(string("davis"), 10, "willy wanka") == "willydavis"));
+ DLIB_TEST( (rpad(string("davis"), 10, "willy wanka") == "daviswilly"));
+ DLIB_TEST( (pad(string("davis"), 10, "willy wanka") == "widaviswil"));
+ dlog << LTRACE << 7;
+
+ a = "file.txt";
+ DLIB_TEST( (left_substr(a,string(".")) == "file"));
+ DLIB_TEST( (left_substr(a,".") == "file"));
+ DLIB_TEST( (right_substr(a,string(".")) == "txt"));
+ DLIB_TEST( (right_substr(a,".") == "txt"));
+
+ DLIB_TEST( (left_substr(a," ") == "file.txt"));
+ DLIB_TEST( (right_substr(a," ") == ""));
+
+ DLIB_TEST( (left_substr(a,"") == "file.txt"));
+ DLIB_TEST( (right_substr(a,"") == ""));
+
+ wstring ws = L"file.txt";
+ DLIB_TEST( (left_substr(ws,wstring(L".")) == L"file"));
+ DLIB_TEST_MSG( (left_substr(ws,L".") == L"file"), L"");
+ DLIB_TEST( (right_substr(ws,wstring(L".")) == L"txt"));
+ DLIB_TEST_MSG( (right_substr(ws,L".") == L"txt"), L"");
+
+
+ dlog << LTRACE << 8;
+ {
+ ostringstream sout;
+ wchar_t w = 85;
+ char c = 4;
+ serialize(w,sout);
+ serialize(c,sout);
+ w = static_cast<wchar_t>(-1);
+ serialize(w,sout);
+ c = static_cast<char>(-1);
+ serialize(c,sout);
+
+ istringstream sin(sout.str());
+ w = 0;
+ c = 0;
+ deserialize(w,sin);
+ deserialize(c,sin);
+ DLIB_TEST(w == 85);
+ DLIB_TEST(c == 4);
+ deserialize(w,sin);
+ deserialize(c,sin);
+ DLIB_TEST(w == static_cast<wchar_t>(-1));
+ DLIB_TEST(c == static_cast<char>(-1));
+
+ wstring str = L"test string";
+
+ sout.str("");
+ serialize(str, sout);
+ sin.clear();
+ sin.str(sout.str());
+ str = L"something else";
+ deserialize(str,sin);
+ DLIB_TEST(str == L"test string");
+ }
+ }
+
+
+ void test_split()
+ {
+ std::vector<string> v;
+
+ string str;
+ string delim = " , ";
+
+ v = split(string("one, two,three four")," ,");
+ DLIB_TEST(v.size() == 4);
+ DLIB_TEST(v[0] == "one");
+ DLIB_TEST(v[1] == "two");
+ DLIB_TEST(v[2] == "three");
+ DLIB_TEST(v[3] == "four");
+
+ v = split(string("one, two,three four"),delim);
+ DLIB_TEST(v.size() == 4);
+ DLIB_TEST(v[0] == "one");
+ DLIB_TEST(v[1] == "two");
+ DLIB_TEST(v[2] == "three");
+ DLIB_TEST(v[3] == "four");
+
+ v = split(string(""));
+ DLIB_TEST(v.size() == 0);
+
+ v = split(string(" "));
+ DLIB_TEST(v.size() == 0);
+
+ v = split(string(" one two "));
+ DLIB_TEST(v.size() == 2);
+ DLIB_TEST(v[0] == "one");
+ DLIB_TEST(v[1] == "two");
+
+ v = split(string(" one "));
+ DLIB_TEST(v.size() == 1);
+ DLIB_TEST(v[0] == "one");
+
+ v = split(string("one"));
+ DLIB_TEST(v.size() == 1);
+ DLIB_TEST(v[0] == "one");
+
+ v = split(string("o"));
+ DLIB_TEST(v.size() == 1);
+ DLIB_TEST(v[0] == "o");
+
+
+ std::vector<wstring> wv;
+ wstring wstr = L"test string";
+ wv = split(wstr);
+ DLIB_TEST(wv.size() == 2);
+ DLIB_TEST(wv[0] == L"test");
+ DLIB_TEST(wv[1] == L"string");
+ wv = split(wstr,L" ");
+ DLIB_TEST(wv.size() == 2);
+ DLIB_TEST(wv[0] == L"test");
+ DLIB_TEST(wv[1] == L"string");
+
+ wstr = L"Über alle Maßen\u00A0Öttingenstraße";
+ wv = split(wstr, L" \u00A0\n\r\t");
+ DLIB_TEST(wv.size() == 4);
+ DLIB_TEST(wv[0] == L"Ãœber");
+ DLIB_TEST(wv[1] == L"alle");
+ DLIB_TEST(wv[2] == L"Maßen");
+ DLIB_TEST(wv[3] == L"Öttingenstraße");
+
+ wstr = L"test string hah";
+ DLIB_TEST(split_on_first(wstr).first == L"test");
+ DLIB_TEST(split_on_first(wstr).second == L"string hah");
+ DLIB_TEST(split_on_first(wstr,L"#").first == L"test string hah");
+ DLIB_TEST(split_on_first(wstr,L"#").second == L"");
+ DLIB_TEST(split_on_last(wstr).first == L"test string");
+ DLIB_TEST(split_on_last(wstr).second == L"hah");
+ DLIB_TEST(split_on_last(wstr,L"#").first == L"test string hah");
+ DLIB_TEST(split_on_last(wstr,L"#").second == L"");
+ wstr = L"";
+ DLIB_TEST(split_on_first(wstr).first == L"");
+ DLIB_TEST(split_on_first(wstr).second == L"");
+
+ str = "test string hah";
+ DLIB_TEST(split_on_first(str).first == "test");
+ DLIB_TEST(split_on_first(str).second == "string hah");
+ DLIB_TEST(split_on_first(str,"#").first == "test string hah");
+ DLIB_TEST(split_on_first(str,"#").second == "");
+ DLIB_TEST(split_on_last(str).first == "test string");
+ DLIB_TEST(split_on_last(str).second == "hah");
+ DLIB_TEST(split_on_last(str,"#").first == "test string hah");
+ DLIB_TEST(split_on_last(str,"#").second == "");
+ str = "";
+ DLIB_TEST(split_on_first(str).first == "");
+ DLIB_TEST(split_on_first(str).second == "");
+
+ wstr = L"test.string.hah";
+ DLIB_TEST(split_on_first(wstr,L".").first == L"test");
+ DLIB_TEST(split_on_first(wstr,L".").second == L"string.hah");
+ DLIB_TEST(split_on_first(wstr).first == L"test.string.hah");
+ DLIB_TEST(split_on_first(wstr).second == L"");
+ DLIB_TEST(split_on_last(wstr,L".").first == L"test.string");
+ DLIB_TEST(split_on_last(wstr,L".").second == L"hah");
+ DLIB_TEST(split_on_last(wstr).first == L"test.string.hah");
+ DLIB_TEST(split_on_last(wstr).second == L"");
+ wstr = L"";
+ DLIB_TEST(split_on_first(wstr).first == L"");
+ DLIB_TEST(split_on_first(wstr).second == L"");
+
+ str = "test.string.hah";
+ DLIB_TEST(split_on_first(str,".").first == "test");
+ DLIB_TEST(split_on_first(str,".").second == "string.hah");
+ DLIB_TEST(split_on_first(str).first == "test.string.hah");
+ DLIB_TEST(split_on_first(str).second == "");
+ DLIB_TEST(split_on_last(str,".").first == "test.string");
+ DLIB_TEST(split_on_last(str,".").second == "hah");
+ DLIB_TEST(split_on_last(str).first == "test.string.hah");
+ DLIB_TEST(split_on_last(str).second == "");
+ str = "";
+ DLIB_TEST(split_on_first(str).first == "");
+ DLIB_TEST(split_on_first(str).second == "");
+ }
+
+
+
+ class string_tester : public tester
+ {
+ public:
+ string_tester (
+ ) :
+ tester ("test_string",
+ "Runs tests on the string objects and functions.")
+ {}
+
+ void perform_test (
+ )
+ {
+ string_test();
+ test_split();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/svm.cpp b/ml/dlib/dlib/test/svm.cpp
new file mode 100644
index 000000000..b46d44331
--- /dev/null
+++ b/ml/dlib/dlib/test/svm.cpp
@@ -0,0 +1,661 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+#include "checkerboard.h"
+#include <dlib/statistics.h>
+
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.svm");
+
+// ----------------------------------------------------------------------------------------
+
+ void test_clutering (
+ )
+ {
+ dlog << LINFO << " being test_clutering()";
+ // Here we declare that our samples will be 2 dimensional column vectors.
+ typedef matrix<double,2,1> sample_type;
+
+ // Now we are making a typedef for the kind of kernel we want to use. I picked the
+ // radial basis kernel because it only has one parameter and generally gives good
+ // results without much fiddling.
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+ // Here we declare an instance of the kcentroid object. The first argument to the constructor
+ // is the kernel we wish to use. The second is a parameter that determines the numerical
+ // accuracy with which the object will perform part of the learning algorithm. Generally
+ // smaller values give better results but cause the algorithm to run slower. You just have
+ // to play with it to decide what balance of speed and accuracy is right for your problem.
+ // Here we have set it to 0.01.
+ kcentroid<kernel_type> kc(kernel_type(0.1),0.01);
+
+ // Now we make an instance of the kkmeans object and tell it to use kcentroid objects
+ // that are configured with the parameters from the kc object we defined above.
+ kkmeans<kernel_type> test(kc);
+
+ std::vector<sample_type> samples;
+ std::vector<sample_type> initial_centers;
+
+ sample_type m;
+
+ dlib::rand rnd;
+
+ print_spinner();
+ // we will make 50 points from each class
+ const long num = 50;
+
+ // make some samples near the origin
+ double radius = 0.5;
+ for (long i = 0; i < num; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ }
+
+ // make some samples in a circle around the origin but far away
+ radius = 10.0;
+ for (long i = 0; i < num; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ }
+
+ // make some samples in a circle around the point (25,25)
+ radius = 4.0;
+ for (long i = 0; i < num; ++i)
+ {
+ double sign = 1;
+ if (rnd.get_random_double() < 0.5)
+ sign = -1;
+ m(0) = 2*radius*rnd.get_random_double()-radius;
+ m(1) = sign*sqrt(radius*radius - m(0)*m(0));
+
+ // translate this point away from the origin
+ m(0) += 25;
+ m(1) += 25;
+
+ // add this sample to our set of samples we will run k-means
+ samples.push_back(m);
+ }
+ print_spinner();
+
+ // tell the kkmeans object we made that we want to run k-means with k set to 3.
+ // (i.e. we want 3 clusters)
+ test.set_number_of_centers(3);
+
+ // You need to pick some initial centers for the k-means algorithm. So here
+ // we will use the dlib::pick_initial_centers() function which tries to find
+ // n points that are far apart (basically).
+ pick_initial_centers(3, initial_centers, samples, test.get_kernel());
+
+ print_spinner();
+ // now run the k-means algorithm on our set of samples.
+ test.train(samples,initial_centers);
+ print_spinner();
+
+ const unsigned long class1 = test(samples[0]);
+ const unsigned long class2 = test(samples[num]);
+ const unsigned long class3 = test(samples[2*num]);
+ // now loop over all our samples and print out their predicted class. In this example
+ // all points are correctly identified.
+ for (unsigned long i = 0; i < samples.size()/3; ++i)
+ {
+ DLIB_TEST(test(samples[i]) == class1);
+ DLIB_TEST(test(samples[i+num]) == class2);
+ DLIB_TEST(test(samples[i+2*num]) == class3);
+ }
+
+ dlog << LINFO << " end test_clutering()";
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ // Here is the sinc function we will be trying to learn with the krls
+ // object.
+ double sinc(double x)
+ {
+ if (x == 0)
+ return 1;
+ return sin(x)/x;
+ }
+
+
+ void test_regression (
+ )
+ {
+ dlog << LINFO << " being test_regression()";
+ // Here we declare that our samples will be 1 dimensional column vectors. The reason for
+ // using a matrix here is that in general you can use N dimensional vectors as inputs to the
+ // krls object. But here we only have 1 dimension to make the example simple.
+ typedef matrix<double,1,1> sample_type;
+
+ // Now we are making a typedef for the kind of kernel we want to use. I picked the
+ // radial basis kernel because it only has one parameter and generally gives good
+ // results without much fiddling.
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+ // Here we declare an instance of the krls object. The first argument to the constructor
+ // is the kernel we wish to use. The second is a parameter that determines the numerical
+ // accuracy with which the object will perform part of the regression algorithm. Generally
+ // smaller values give better results but cause the algorithm to run slower. You just have
+ // to play with it to decide what balance of speed and accuracy is right for your problem.
+ // Here we have set it to 0.001.
+ krls<kernel_type> test(kernel_type(0.1),0.001);
+ rvm_regression_trainer<kernel_type> rvm_test;
+ rvm_test.set_kernel(test.get_kernel());
+
+ krr_trainer<kernel_type> krr_test;
+ krr_test.set_kernel(test.get_kernel());
+
+ svr_trainer<kernel_type> svr_test;
+ svr_test.set_kernel(test.get_kernel());
+ svr_test.set_epsilon_insensitivity(0.0001);
+ svr_test.set_c(10);
+
+ rbf_network_trainer<kernel_type> rbf_test;
+ rbf_test.set_kernel(test.get_kernel());
+ rbf_test.set_num_centers(13);
+
+ print_spinner();
+ std::vector<sample_type> samples;
+ std::vector<sample_type> samples2;
+ std::vector<double> labels;
+ std::vector<double> labels2;
+ // now we train our object on a few samples of the sinc function.
+ sample_type m;
+ for (double x = -10; x <= 5; x += 0.6)
+ {
+ m(0) = x;
+ test.train(m, sinc(x));
+
+ samples.push_back(m);
+ samples2.push_back(m);
+ labels.push_back(sinc(x));
+ labels2.push_back(2);
+ }
+
+ print_spinner();
+ decision_function<kernel_type> test2 = rvm_test.train(samples, labels);
+ print_spinner();
+ decision_function<kernel_type> test3 = rbf_test.train(samples, labels);
+ print_spinner();
+ decision_function<kernel_type> test4 = krr_test.train(samples, labels);
+ print_spinner();
+ decision_function<kernel_type> test5 = svr_test.train(samples, labels);
+ print_spinner();
+
+ // now we output the value of the sinc function for a few test points as well as the
+ // value predicted by krls object.
+ m(0) = 2.5; dlog << LDEBUG << "krls: " << sinc(m(0)) << " " << test(m); DLIB_TEST(abs(sinc(m(0)) - test(m)) < 0.01);
+ m(0) = 0.1; dlog << LDEBUG << "krls: " << sinc(m(0)) << " " << test(m); DLIB_TEST(abs(sinc(m(0)) - test(m)) < 0.01);
+ m(0) = -4; dlog << LDEBUG << "krls: " << sinc(m(0)) << " " << test(m); DLIB_TEST(abs(sinc(m(0)) - test(m)) < 0.01);
+ m(0) = 5.0; dlog << LDEBUG << "krls: " << sinc(m(0)) << " " << test(m); DLIB_TEST(abs(sinc(m(0)) - test(m)) < 0.01);
+
+ m(0) = 2.5; dlog << LDEBUG << "rvm: " << sinc(m(0)) << " " << test2(m); DLIB_TEST(abs(sinc(m(0)) - test2(m)) < 0.01);
+ m(0) = 0.1; dlog << LDEBUG << "rvm: " << sinc(m(0)) << " " << test2(m); DLIB_TEST(abs(sinc(m(0)) - test2(m)) < 0.01);
+ m(0) = -4; dlog << LDEBUG << "rvm: " << sinc(m(0)) << " " << test2(m); DLIB_TEST(abs(sinc(m(0)) - test2(m)) < 0.01);
+ m(0) = 5.0; dlog << LDEBUG << "rvm: " << sinc(m(0)) << " " << test2(m); DLIB_TEST(abs(sinc(m(0)) - test2(m)) < 0.01);
+
+ m(0) = 2.5; dlog << LDEBUG << "rbf: " << sinc(m(0)) << " " << test3(m); DLIB_TEST(abs(sinc(m(0)) - test3(m)) < 0.01);
+ m(0) = 0.1; dlog << LDEBUG << "rbf: " << sinc(m(0)) << " " << test3(m); DLIB_TEST(abs(sinc(m(0)) - test3(m)) < 0.01);
+ m(0) = -4; dlog << LDEBUG << "rbf: " << sinc(m(0)) << " " << test3(m); DLIB_TEST(abs(sinc(m(0)) - test3(m)) < 0.01);
+ m(0) = 5.0; dlog << LDEBUG << "rbf: " << sinc(m(0)) << " " << test3(m); DLIB_TEST(abs(sinc(m(0)) - test3(m)) < 0.01);
+
+ m(0) = 2.5; dlog << LDEBUG << "krr: " << sinc(m(0)) << " " << test4(m); DLIB_TEST(abs(sinc(m(0)) - test4(m)) < 0.01);
+ m(0) = 0.1; dlog << LDEBUG << "krr: " << sinc(m(0)) << " " << test4(m); DLIB_TEST(abs(sinc(m(0)) - test4(m)) < 0.01);
+ m(0) = -4; dlog << LDEBUG << "krr: " << sinc(m(0)) << " " << test4(m); DLIB_TEST(abs(sinc(m(0)) - test4(m)) < 0.01);
+ m(0) = 5.0; dlog << LDEBUG << "krr: " << sinc(m(0)) << " " << test4(m); DLIB_TEST(abs(sinc(m(0)) - test4(m)) < 0.01);
+
+ m(0) = 2.5; dlog << LDEBUG << "svr: " << sinc(m(0)) << " " << test5(m); DLIB_TEST(abs(sinc(m(0)) - test5(m)) < 0.01);
+ m(0) = 0.1; dlog << LDEBUG << "svr: " << sinc(m(0)) << " " << test5(m); DLIB_TEST(abs(sinc(m(0)) - test5(m)) < 0.01);
+ m(0) = -4; dlog << LDEBUG << "svr: " << sinc(m(0)) << " " << test5(m); DLIB_TEST(abs(sinc(m(0)) - test5(m)) < 0.01);
+ m(0) = 5.0; dlog << LDEBUG << "svr: " << sinc(m(0)) << " " << test5(m); DLIB_TEST(abs(sinc(m(0)) - test5(m)) < 0.01);
+
+
+ randomize_samples(samples, labels);
+ dlog << LINFO << "KRR MSE and R-squared: "<< cross_validate_regression_trainer(krr_test, samples, labels, 6);
+ dlog << LINFO << "SVR MSE and R-squared: "<< cross_validate_regression_trainer(svr_test, samples, labels, 6);
+ matrix<double,1,4> cv = cross_validate_regression_trainer(krr_test, samples, labels, 6);
+ DLIB_TEST(cv(0) < 1e-4);
+ DLIB_TEST(cv(1) > 0.99);
+ cv = cross_validate_regression_trainer(svr_test, samples, labels, 6);
+ DLIB_TEST(cv(0) < 1e-4);
+ DLIB_TEST(cv(1) > 0.99);
+
+
+
+
+ randomize_samples(samples2, labels2);
+ dlog << LINFO << "KRR MSE and R-squared: "<< cross_validate_regression_trainer(krr_test, samples2, labels2, 6);
+ dlog << LINFO << "SVR MSE and R-squared: "<< cross_validate_regression_trainer(svr_test, samples2, labels2, 6);
+ cv = cross_validate_regression_trainer(krr_test, samples2, labels2, 6);
+ DLIB_TEST(cv(0) < 1e-4);
+ cv = cross_validate_regression_trainer(svr_test, samples2, labels2, 6);
+ DLIB_TEST(cv(0) < 1e-4);
+
+ dlog << LINFO << " end test_regression()";
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_anomaly_detection (
+ )
+ {
+ dlog << LINFO << " begin test_anomaly_detection()";
+ // Here we declare that our samples will be 2 dimensional column vectors.
+ typedef matrix<double,2,1> sample_type;
+
+ // Now we are making a typedef for the kind of kernel we want to use. I picked the
+ // radial basis kernel because it only has one parameter and generally gives good
+ // results without much fiddling.
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+ // Here we declare an instance of the kcentroid object. The first argument to the constructor
+ // is the kernel we wish to use. The second is a parameter that determines the numerical
+ // accuracy with which the object will perform part of the learning algorithm. Generally
+ // smaller values give better results but cause the algorithm to run slower. You just have
+ // to play with it to decide what balance of speed and accuracy is right for your problem.
+ // Here we have set it to 0.01.
+ kcentroid<kernel_type> test(kernel_type(0.1),0.01);
+
+
+ svm_one_class_trainer<kernel_type> one_class_trainer;
+ one_class_trainer.set_nu(0.4);
+ one_class_trainer.set_kernel(kernel_type(0.2));
+
+ std::vector<sample_type> samples;
+
+ // now we train our object on a few samples of the sinc function.
+ sample_type m;
+ for (double x = -15; x <= 8; x += 1)
+ {
+ m(0) = x;
+ m(1) = sinc(x);
+ test.train(m);
+ samples.push_back(m);
+ }
+
+ decision_function<kernel_type> df = one_class_trainer.train(samples);
+
+ running_stats<double> rs;
+
+ // Now lets output the distance from the centroid to some points that are from the sinc function.
+ // These numbers should all be similar. We will also calculate the statistics of these numbers
+ // by accumulating them into the running_stats object called rs. This will let us easily
+ // find the mean and standard deviation of the distances for use below.
+ dlog << LDEBUG << "Points that are on the sinc function:\n";
+ m(0) = -1.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m));
+ m(0) = -1.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m));
+ m(0) = -0; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m));
+ m(0) = -0.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m));
+ m(0) = -4.1; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m));
+ m(0) = -1.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m));
+ m(0) = -0.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m));
+
+ m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m)));
+ m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m)));
+ m(0) = -0; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m)));
+ m(0) = -0.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m)));
+ m(0) = -4.1; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m)));
+ m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m)));
+ m(0) = -0.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m)));
+
+ const double thresh = 0.01;
+ m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m));
+ m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m));
+ m(0) = -0; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m));
+ m(0) = -0.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m));
+ m(0) = -4.1; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m));
+ m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m));
+ m(0) = -0.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m));
+
+ dlog << LDEBUG;
+ // Lets output the distance from the centroid to some points that are NOT from the sinc function.
+ // These numbers should all be significantly bigger than previous set of numbers. We will also
+ // use the rs.scale() function to find out how many standard deviations they are away from the
+ // mean of the test points from the sinc function. So in this case our criterion for "significantly bigger"
+ // is > 3 or 4 standard deviations away from the above points that actually are on the sinc function.
+ dlog << LDEBUG << "Points that are NOT on the sinc function:\n";
+ m(0) = -1.5; m(1) = sinc(m(0))+4;
+ dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc.";
+ DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m)));
+ DLIB_TEST_MSG(df(m) + thresh < 0, df(m));
+
+ m(0) = -1.5; m(1) = sinc(m(0))+3;
+ dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc.";
+ DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m)));
+ DLIB_TEST_MSG(df(m) + thresh < 0, df(m));
+
+ m(0) = -0; m(1) = -sinc(m(0));
+ dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc.";
+ DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m)));
+ DLIB_TEST_MSG(df(m) + thresh < 0, df(m));
+
+ m(0) = -0.5; m(1) = -sinc(m(0));
+ dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc.";
+ DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m)));
+ DLIB_TEST_MSG(df(m) + thresh < 0, df(m));
+
+ m(0) = -4.1; m(1) = sinc(m(0))+2;
+ dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc.";
+ DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m)));
+ DLIB_TEST_MSG(df(m) + thresh < 0, df(m));
+
+ m(0) = -1.5; m(1) = sinc(m(0))+0.9;
+ dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc.";
+ DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m)));
+ DLIB_TEST_MSG(df(m) + thresh < 0, df(m));
+
+ m(0) = -0.5; m(1) = sinc(m(0))+1;
+ dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc.";
+ DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m)));
+ DLIB_TEST_MSG(df(m) + thresh < 0, df(m));
+
+ dlog << LINFO << " end test_anomaly_detection()";
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void unittest_binary_classification (
+ )
+ /*!
+ ensures
+ - runs tests on the svm stuff compliance with the specs
+ !*/
+ {
+ dlog << LINFO << " begin unittest_binary_classification()";
+ print_spinner();
+
+
+ typedef double scalar_type;
+ typedef matrix<scalar_type,2,1> sample_type;
+
+ std::vector<sample_type> x;
+ std::vector<matrix<double,0,1> > x_linearized;
+ std::vector<scalar_type> y;
+
+ get_checkerboard_problem(x,y, 300, 2);
+ const scalar_type gamma = 1;
+
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+ rbf_network_trainer<kernel_type> rbf_trainer;
+ rbf_trainer.set_kernel(kernel_type(gamma));
+ rbf_trainer.set_num_centers(100);
+
+ rvm_trainer<kernel_type> rvm_trainer;
+ rvm_trainer.set_kernel(kernel_type(gamma));
+
+ krr_trainer<kernel_type> krr_trainer;
+ krr_trainer.use_classification_loss_for_loo_cv();
+ krr_trainer.set_kernel(kernel_type(gamma));
+
+ svm_pegasos<kernel_type> pegasos_trainer;
+ pegasos_trainer.set_kernel(kernel_type(gamma));
+ pegasos_trainer.set_lambda(0.00001);
+
+
+ svm_c_ekm_trainer<kernel_type> ocas_ekm_trainer;
+ ocas_ekm_trainer.set_kernel(kernel_type(gamma));
+ ocas_ekm_trainer.set_c(100000);
+
+ svm_nu_trainer<kernel_type> trainer;
+ trainer.set_kernel(kernel_type(gamma));
+ trainer.set_nu(0.05);
+
+ svm_c_trainer<kernel_type> c_trainer;
+ c_trainer.set_kernel(kernel_type(gamma));
+ c_trainer.set_c(100);
+
+ svm_c_linear_trainer<linear_kernel<matrix<double,0,1> > > lin_trainer;
+ lin_trainer.set_c(100000);
+ // use an ekm to linearize this dataset so we can use it with the lin_trainer
+ empirical_kernel_map<kernel_type> ekm;
+ ekm.load(kernel_type(gamma), x);
+ for (unsigned long i = 0; i < x.size(); ++i)
+ x_linearized.push_back(ekm.project(x[i]));
+
+
+ print_spinner();
+ matrix<scalar_type> rvm_cv = cross_validate_trainer_threaded(rvm_trainer, x,y, 4, 2);
+ print_spinner();
+ matrix<scalar_type> krr_cv = cross_validate_trainer_threaded(krr_trainer, x,y, 4, 2);
+ print_spinner();
+ matrix<scalar_type> svm_cv = cross_validate_trainer(trainer, x,y, 4);
+ print_spinner();
+ matrix<scalar_type> svm_c_cv = cross_validate_trainer(c_trainer, x,y, 4);
+ print_spinner();
+ matrix<scalar_type> rbf_cv = cross_validate_trainer_threaded(rbf_trainer, x,y, 10, 2);
+ print_spinner();
+ matrix<scalar_type> lin_cv = cross_validate_trainer_threaded(lin_trainer, x_linearized, y, 4, 2);
+ print_spinner();
+ matrix<scalar_type> ocas_ekm_cv = cross_validate_trainer_threaded(ocas_ekm_trainer, x, y, 4, 2);
+ print_spinner();
+ ocas_ekm_trainer.set_basis(randomly_subsample(x, 300));
+ matrix<scalar_type> ocas_ekm_cv2 = cross_validate_trainer_threaded(ocas_ekm_trainer, x, y, 4, 2);
+ print_spinner();
+ matrix<scalar_type> peg_cv = cross_validate_trainer_threaded(batch(pegasos_trainer,1.0), x,y, 4, 2);
+ print_spinner();
+ matrix<scalar_type> peg_c_cv = cross_validate_trainer_threaded(batch_cached(pegasos_trainer,1.0), x,y, 4, 2);
+ print_spinner();
+
+ dlog << LDEBUG << "rvm cv: " << rvm_cv;
+ dlog << LDEBUG << "krr cv: " << krr_cv;
+ dlog << LDEBUG << "nu-svm cv: " << svm_cv;
+ dlog << LDEBUG << "C-svm cv: " << svm_c_cv;
+ dlog << LDEBUG << "rbf cv: " << rbf_cv;
+ dlog << LDEBUG << "lin cv: " << lin_cv;
+ dlog << LDEBUG << "ocas_ekm cv: " << ocas_ekm_cv;
+ dlog << LDEBUG << "ocas_ekm cv2: " << ocas_ekm_cv2;
+ dlog << LDEBUG << "peg cv: " << peg_cv;
+ dlog << LDEBUG << "peg cached cv: " << peg_c_cv;
+
+ // make sure the cached version of pegasos computes the same result
+ DLIB_TEST_MSG(sum(abs(peg_cv - peg_c_cv)) < std::sqrt(std::numeric_limits<double>::epsilon()),
+ sum(abs(peg_cv - peg_c_cv)) << " \n" << peg_cv << peg_c_cv );
+
+ DLIB_TEST_MSG(mean(rvm_cv) > 0.9, rvm_cv);
+ DLIB_TEST_MSG(mean(krr_cv) > 0.9, krr_cv);
+ DLIB_TEST_MSG(mean(svm_cv) > 0.9, svm_cv);
+ DLIB_TEST_MSG(mean(svm_c_cv) > 0.9, svm_c_cv);
+ DLIB_TEST_MSG(mean(rbf_cv) > 0.9, rbf_cv);
+ DLIB_TEST_MSG(mean(lin_cv) > 0.9, lin_cv);
+ DLIB_TEST_MSG(mean(peg_cv) > 0.9, peg_cv);
+ DLIB_TEST_MSG(mean(peg_c_cv) > 0.9, peg_c_cv);
+ DLIB_TEST_MSG(mean(ocas_ekm_cv) > 0.9, ocas_ekm_cv);
+ DLIB_TEST_MSG(mean(ocas_ekm_cv2) > 0.9, ocas_ekm_cv2);
+
+ const long num_sv = trainer.train(x,y).basis_vectors.size();
+ print_spinner();
+ const long num_rv = rvm_trainer.train(x,y).basis_vectors.size();
+ print_spinner();
+ dlog << LDEBUG << "num sv: " << num_sv;
+ dlog << LDEBUG << "num rv: " << num_rv;
+ print_spinner();
+ ocas_ekm_trainer.clear_basis();
+ const long num_bv = ocas_ekm_trainer.train(x,y).basis_vectors.size();
+ dlog << LDEBUG << "num ekm bv: " << num_bv;
+
+ DLIB_TEST(num_rv <= 17);
+ DLIB_TEST_MSG(num_sv <= 45, num_sv);
+ DLIB_TEST_MSG(num_bv <= 45, num_bv);
+
+ decision_function<kernel_type> df = reduced2(trainer, 19).train(x,y);
+ print_spinner();
+
+ matrix<scalar_type> svm_reduced_error = test_binary_decision_function(df, x, y);
+ print_spinner();
+ dlog << LDEBUG << "svm reduced test error: " << svm_reduced_error;
+ dlog << LDEBUG << "svm reduced num sv: " << df.basis_vectors.size();
+ DLIB_TEST(mean(svm_reduced_error) > 0.9);
+
+ svm_cv = cross_validate_trainer(reduced(trainer,30), x,y, 4);
+ dlog << LDEBUG << "svm reduced cv: " << svm_cv;
+ DLIB_TEST_MSG(mean(svm_cv) > 0.9, svm_cv);
+
+ DLIB_TEST(df.basis_vectors.size() <= 19);
+ dlog << LINFO << " end unittest_binary_classification()";
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename kernel_type>
+ struct kernel_der_obj
+ {
+ typename kernel_type::sample_type x;
+ kernel_type k;
+
+ double operator()(const typename kernel_type::sample_type& y) const { return k(x,y); }
+ };
+
+
+ template <typename kernel_type>
+ void test_kernel_derivative (
+ const kernel_type& k,
+ const typename kernel_type::sample_type& x,
+ const typename kernel_type::sample_type& y
+ )
+ {
+ kernel_der_obj<kernel_type> obj;
+ obj.x = x;
+ obj.k = k;
+ kernel_derivative<kernel_type> der(obj.k);
+ DLIB_TEST(dlib::equal(derivative(obj)(y) , der(obj.x,y), 1e-5));
+ }
+
+ void test_kernel_derivative (
+ )
+ {
+ typedef matrix<double, 2, 1> sample_type;
+
+ sigmoid_kernel<sample_type> k1;
+ radial_basis_kernel<sample_type> k2;
+ linear_kernel<sample_type> k3;
+ polynomial_kernel<sample_type> k4(2,3,4);
+
+ offset_kernel<sigmoid_kernel<sample_type> > k5;
+ offset_kernel<radial_basis_kernel<sample_type> > k6;
+
+ dlib::rand rnd;
+
+ sample_type x, y;
+ for (int i = 0; i < 10; ++i)
+ {
+ x = randm(2,1,rnd);
+ y = randm(2,1,rnd);
+ test_kernel_derivative(k1, x, y);
+ test_kernel_derivative(k2, x, y);
+ test_kernel_derivative(k3, x, y);
+ test_kernel_derivative(k4, x, y);
+ test_kernel_derivative(k5, x, y);
+ test_kernel_derivative(k6, x, y);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_svm_trainer2()
+ {
+ typedef matrix<double, 2, 1> sample_type;
+ typedef linear_kernel<sample_type> kernel_type;
+
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ sample_type samp;
+ samp(0) = 1;
+ samp(1) = 1;
+ samples.push_back(samp);
+ labels.push_back(+1);
+
+ samp(0) = 1;
+ samp(1) = 2;
+ samples.push_back(samp);
+ labels.push_back(-1);
+
+ svm_c_trainer<kernel_type> trainer;
+
+ decision_function<kernel_type> df = trainer.train(samples, labels);
+
+ samp(0) = 1;
+ samp(1) = 1;
+ dlog << LINFO << "test +1 : "<< df(samp);
+ DLIB_TEST(df(samp) > 0);
+ samp(0) = 1;
+ samp(1) = 2;
+ dlog << LINFO << "test -1 : "<< df(samp);
+ DLIB_TEST(df(samp) < 0);
+
+ svm_nu_trainer<kernel_type> trainer2;
+ df = trainer2.train(samples, labels);
+
+ samp(0) = 1;
+ samp(1) = 1;
+ dlog << LINFO << "test +1 : "<< df(samp);
+ DLIB_TEST(df(samp) > 0);
+ samp(0) = 1;
+ samp(1) = 2;
+ dlog << LINFO << "test -1 : "<< df(samp);
+ DLIB_TEST(df(samp) < 0);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class svm_tester : public tester
+ {
+ public:
+ svm_tester (
+ ) :
+ tester ("test_svm",
+ "Runs tests on the svm/kernel algorithm components.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_kernel_derivative();
+ unittest_binary_classification();
+ test_clutering();
+ test_regression();
+ test_anomaly_detection();
+ test_svm_trainer2();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/svm_c_linear.cpp b/ml/dlib/dlib/test/svm_c_linear.cpp
new file mode 100644
index 000000000..9e30d81f7
--- /dev/null
+++ b/ml/dlib/dlib/test/svm_c_linear.cpp
@@ -0,0 +1,392 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../stl_checked.h"
+#include "../array.h"
+#include "../rand.h"
+#include "checkerboard.h"
+#include <dlib/statistics.h>
+
+#include "tester.h"
+#include <dlib/svm.h>
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.svm_c_linear");
+
+ typedef matrix<double, 0, 1> sample_type;
+ typedef std::vector<std::pair<unsigned int, double> > sparse_sample_type;
+
+// ----------------------------------------------------------------------------------------
+
+ void run_prior_test()
+ {
+ typedef matrix<double,3,1> sample_type;
+ typedef linear_kernel<sample_type> kernel_type;
+
+ svm_c_linear_trainer<kernel_type> trainer;
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ sample_type samp;
+ samp = 0, 0, 1; samples.push_back(samp); labels.push_back(+1);
+ samp = 0, 1, 0; samples.push_back(samp); labels.push_back(-1);
+
+ trainer.set_c(10);
+ decision_function<kernel_type> df = trainer.train(samples, labels);
+
+ trainer.set_prior(df);
+
+ samples.clear();
+ labels.clear();
+ samp = 1, 0, 0; samples.push_back(samp); labels.push_back(+1);
+ samp = 0, 1, 0; samples.push_back(samp); labels.push_back(-1);
+
+ df = trainer.train(samples, labels);
+
+ samp = 0, 0, 1; samples.push_back(samp); labels.push_back(+1);
+ matrix<double,1,2> rs = test_binary_decision_function(df, samples, labels);
+ dlog << LINFO << rs;
+ DLIB_TEST(rs(0) == 1);
+ DLIB_TEST(rs(1) == 1);
+
+ dlog << LINFO << trans(df.basis_vectors(0));
+ DLIB_TEST(df.basis_vectors(0)(0) > 0);
+ DLIB_TEST(df.basis_vectors(0)(1) < 0);
+ DLIB_TEST(df.basis_vectors(0)(2) > 0);
+ }
+
+ void run_prior_sparse_test()
+ {
+ typedef std::map<unsigned long,double> sample_type;
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+
+ svm_c_linear_trainer<kernel_type> trainer;
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ sample_type samp;
+ samp[0] = 1; samples.push_back(samp); labels.push_back(+1); samp.clear();
+ samp[1] = 1; samples.push_back(samp); labels.push_back(-1); samp.clear();
+
+ trainer.set_c(10);
+ decision_function<kernel_type> df = trainer.train(samples, labels);
+
+ trainer.set_prior(df);
+
+ samples.clear();
+ labels.clear();
+ samp[2] = 1; samples.push_back(samp); labels.push_back(+1); samp.clear();
+ samp[1] = 1; samples.push_back(samp); labels.push_back(-1); samp.clear();
+
+ df = trainer.train(samples, labels);
+
+ matrix<double,1,2> rs = test_binary_decision_function(df, samples, labels);
+ dlog << LINFO << rs;
+ DLIB_TEST(rs(0) == 1);
+ DLIB_TEST(rs(1) == 1);
+
+ matrix<double,0,1> w = sparse_to_dense(df.basis_vectors(0));
+ dlog << LINFO << trans(w);
+ DLIB_TEST(w(0) > 0.1);
+ DLIB_TEST(w(1) < -0.1);
+ DLIB_TEST(w(2) > 0.1);
+ }
+
+ void get_simple_points (
+ std::vector<sample_type>& samples,
+ std::vector<double>& labels
+ )
+ {
+ samples.clear();
+ labels.clear();
+ sample_type samp(2);
+
+ samp = 0,0;
+ samples.push_back(samp);
+ labels.push_back(-1);
+
+ samp = 0,1;
+ samples.push_back(samp);
+ labels.push_back(-1);
+
+ samp = 3,0;
+ samples.push_back(samp);
+ labels.push_back(+1);
+
+ samp = 3,1;
+ samples.push_back(samp);
+ labels.push_back(+1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void get_simple_points_sparse (
+ std::vector<sparse_sample_type>& samples,
+ std::vector<double>& labels
+ )
+ {
+ samples.clear();
+ labels.clear();
+ sparse_sample_type samp;
+
+ samp.push_back(make_pair(0, 0.0));
+ samp.push_back(make_pair(1, 0.0));
+ samples.push_back(samp);
+ labels.push_back(-1);
+
+ samp.clear();
+ samp.push_back(make_pair(0, 0.0));
+ samp.push_back(make_pair(1, 1.0));
+ samples.push_back(samp);
+ labels.push_back(-1);
+
+ samp.clear();
+ samp.push_back(make_pair(0, 3.0));
+ samp.push_back(make_pair(1, 0.0));
+ samples.push_back(samp);
+ labels.push_back(+1);
+
+ samp.clear();
+ samp.push_back(make_pair(0, 3.0));
+ samp.push_back(make_pair(1, 1.0));
+ samples.push_back(samp);
+ labels.push_back(+1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_sparse (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test with sparse vectors";
+ std::vector<sparse_sample_type> samples;
+ std::vector<double> labels;
+
+ sample_type samp;
+
+ get_simple_points_sparse(samples,labels);
+
+ svm_c_linear_trainer<sparse_linear_kernel<sparse_sample_type> > trainer;
+ trainer.set_c(1e4);
+ //trainer.be_verbose();
+ trainer.set_epsilon(1e-11);
+
+
+ double obj;
+ decision_function<sparse_linear_kernel<sparse_sample_type> > df = trainer.train(samples, labels, obj);
+ dlog << LDEBUG << "obj: "<< obj;
+ DLIB_TEST_MSG(abs(obj - 0.72222222222) < 1e-7, obj);
+
+ DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6);
+
+
+ // While we are at it, make sure the krr_trainer works with sparse samples
+ krr_trainer<sparse_linear_kernel<sparse_sample_type> > krr;
+
+ df = krr.train(samples, labels);
+ DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6);
+
+
+ // Now test some of the sparse helper functions
+ DLIB_TEST(max_index_plus_one(samples) == 2);
+ DLIB_TEST(max_index_plus_one(samples[0]) == 2);
+
+ matrix<double,3,1> m;
+ m = 1;
+ add_to(m, samples[3]);
+ DLIB_TEST(m(0) == 1 + samples[3][0].second);
+ DLIB_TEST(m(1) == 1 + samples[3][1].second);
+ DLIB_TEST(m(2) == 1);
+
+ m = 1;
+ subtract_from(m, samples[3]);
+ DLIB_TEST(m(0) == 1 - samples[3][0].second);
+ DLIB_TEST(m(1) == 1 - samples[3][1].second);
+ DLIB_TEST(m(2) == 1);
+
+ m = 1;
+ add_to(m, samples[3], 2);
+ DLIB_TEST(m(0) == 1 + 2*samples[3][0].second);
+ DLIB_TEST(m(1) == 1 + 2*samples[3][1].second);
+ DLIB_TEST(m(2) == 1);
+
+ m = 1;
+ subtract_from(m, samples[3], 2);
+ DLIB_TEST(m(0) == 1 - 2*samples[3][0].second);
+ DLIB_TEST(m(1) == 1 - 2*samples[3][1].second);
+ DLIB_TEST(m(2) == 1);
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_dense (
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "test with dense vectors";
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ sample_type samp;
+
+ get_simple_points(samples,labels);
+
+ svm_c_linear_trainer<linear_kernel<sample_type> > trainer;
+ trainer.set_c(1e4);
+ //trainer.be_verbose();
+ trainer.set_epsilon(1e-11);
+
+
+ double obj;
+ decision_function<linear_kernel<sample_type> > df = trainer.train(samples, labels, obj);
+ dlog << LDEBUG << "obj: "<< obj;
+ DLIB_TEST_MSG(abs(obj - 0.72222222222) < 1e-7, abs(obj - 0.72222222222));
+ // There shouldn't be any margin violations since this dataset is so trivial. So that means the objective
+ // should be exactly the squared norm of the decision plane (times 0.5).
+ DLIB_TEST_MSG(abs(length_squared(df.basis_vectors(0))*0.5 + df.b*df.b*0.5 - 0.72222222222) < 1e-7,
+ length_squared(df.basis_vectors(0))*0.5 + df.b*df.b*0.5);
+
+ DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6);
+ DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class tester_svm_c_linear : public tester
+ {
+ public:
+ tester_svm_c_linear (
+ ) :
+ tester ("test_svm_c_linear",
+ "Runs tests on the svm_c_linear_trainer.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_dense();
+ test_sparse();
+ run_prior_test();
+ run_prior_sparse_test();
+
+ // test mixed sparse and dense dot products
+ {
+ std::map<unsigned int, double> sv;
+ matrix<double,0,1> dv(4);
+
+ dv = 1,2,3,4;
+
+ sv[0] = 1;
+ sv[3] = 1;
+
+
+ DLIB_TEST(dot(sv,dv) == 5);
+ DLIB_TEST(dot(dv,sv) == 5);
+ DLIB_TEST(dot(dv,dv) == 30);
+ DLIB_TEST(dot(sv,sv) == 2);
+
+ sv[10] = 9;
+ DLIB_TEST(dot(sv,dv) == 5);
+ }
+
+ // test mixed sparse dense assignments
+ {
+ std::map<unsigned int, double> sv, sv2;
+ std::vector<std::pair<unsigned int, double> > sv3;
+ matrix<double,0,1> dv(4), dv2;
+
+ dv = 1,2,3,4;
+
+ sv[0] = 1;
+ sv[3] = 1;
+
+
+ assign(dv2, dv);
+
+ DLIB_TEST(dv2.size() == 4);
+ DLIB_TEST(dv2(0) == 1);
+ DLIB_TEST(dv2(1) == 2);
+ DLIB_TEST(dv2(2) == 3);
+ DLIB_TEST(dv2(3) == 4);
+
+ assign(sv2, dv);
+ DLIB_TEST(sv2.size() == 4);
+ DLIB_TEST(sv2[0] == 1);
+ DLIB_TEST(sv2[1] == 2);
+ DLIB_TEST(sv2[2] == 3);
+ DLIB_TEST(sv2[3] == 4);
+
+ assign(sv2, sv);
+ DLIB_TEST(sv2.size() == 2);
+ DLIB_TEST(sv2[0] == 1);
+ DLIB_TEST(sv2[1] == 0);
+ DLIB_TEST(sv2[2] == 0);
+ DLIB_TEST(sv2[3] == 1);
+
+ assign(sv3, sv);
+ DLIB_TEST(sv3.size() == 2);
+ DLIB_TEST(sv3[0].second == 1);
+ DLIB_TEST(sv3[1].second == 1);
+ DLIB_TEST(sv3[0].first == 0);
+ DLIB_TEST(sv3[1].first == 3);
+
+ assign(sv3, dv);
+ DLIB_TEST(sv3.size() == 4);
+ DLIB_TEST(sv3[0].second == 1);
+ DLIB_TEST(sv3[1].second == 2);
+ DLIB_TEST(sv3[2].second == 3);
+ DLIB_TEST(sv3[3].second == 4);
+ DLIB_TEST(sv3[0].first == 0);
+ DLIB_TEST(sv3[1].first == 1);
+ DLIB_TEST(sv3[2].first == 2);
+ DLIB_TEST(sv3[3].first == 3);
+
+ assign(sv3, sv);
+ DLIB_TEST(sv3.size() == 2);
+ DLIB_TEST(sv3[0].second == 1);
+ DLIB_TEST(sv3[1].second == 1);
+ DLIB_TEST(sv3[0].first == 0);
+ DLIB_TEST(sv3[1].first == 3);
+
+ sv.clear();
+ assign(sv, sv3);
+ DLIB_TEST(sv.size() == 2);
+ DLIB_TEST(sv[0] == 1);
+ DLIB_TEST(sv[1] == 0);
+ DLIB_TEST(sv[2] == 0);
+ DLIB_TEST(sv[3] == 1);
+
+ }
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/svm_c_linear_dcd.cpp b/ml/dlib/dlib/test/svm_c_linear_dcd.cpp
new file mode 100644
index 000000000..93c99db30
--- /dev/null
+++ b/ml/dlib/dlib/test/svm_c_linear_dcd.cpp
@@ -0,0 +1,545 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/svm.h>
+#include <dlib/rand.h>
+#include <dlib/statistics.h>
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.svm_c_linear_dcd");
+
+// ----------------------------------------------------------------------------------------
+
+ void test_sparse()
+ {
+ typedef std::map<unsigned long,double> sample_type;
+
+
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+
+
+
+ svm_c_linear_trainer<kernel_type> linear_trainer_cpa;
+ svm_c_linear_dcd_trainer<kernel_type> linear_trainer;
+
+ svm_c_linear_dcd_trainer<kernel_type>::optimizer_state state;
+
+ const double C = 0.2;
+ linear_trainer.set_epsilon(1e-10);
+ linear_trainer_cpa.set_epsilon(1e-10);
+
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ // make an instance of a sample vector so we can use it below
+ sample_type sample;
+
+ decision_function<kernel_type> df, df2, df3;
+
+ dlib::rand rnd;
+ // Now lets go into a loop and randomly generate 10000 samples.
+ double label = +1;
+ for (int i = 0; i < 100; ++i)
+ {
+ // flip this flag
+ label *= -1;
+
+ sample.clear();
+
+ // now make a random sparse sample with at most 10 non-zero elements
+ for (int j = 0; j < 5; ++j)
+ {
+ int idx = rnd.get_random_32bit_number()%10;
+ double value = rnd.get_random_double();
+
+ sample[idx] = label*value;
+ }
+
+ // Also save the samples we are generating so we can let the svm_c_linear_trainer
+ // learn from them below.
+ samples.push_back(sample);
+ labels.push_back(label);
+
+ if (samples.size() > 1)
+ {
+ linear_trainer_cpa.set_c_class1(C);
+ linear_trainer_cpa.set_c_class2(1.5*C);
+ linear_trainer.set_c_class1(C/samples.size());
+ linear_trainer.set_c_class2(1.5*C/samples.size());
+
+ df = linear_trainer.train(samples, labels, state);
+ df2 = linear_trainer_cpa.train(samples, labels);
+ df3 = linear_trainer.train(samples, labels);
+
+ DLIB_TEST_MSG( dlib::distance(df.basis_vectors(0), df2.basis_vectors(0)) < 1e-8, dlib::distance(df.basis_vectors(0), df2.basis_vectors(0)));
+ DLIB_TEST( std::abs(df.b - df2.b) < 1e-8);
+ DLIB_TEST( dlib::distance(df.basis_vectors(0), df3.basis_vectors(0)) < 1e-8);
+ DLIB_TEST( std::abs(df.b - df3.b) < 1e-8);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_normal_no_bias()
+ {
+ typedef matrix<double,10,1> sample_type;
+
+
+ typedef linear_kernel<sample_type> kernel_type;
+
+
+
+ svm_c_linear_trainer<kernel_type> linear_trainer_cpa;
+ svm_c_linear_dcd_trainer<kernel_type> linear_trainer;
+
+ svm_c_linear_dcd_trainer<kernel_type>::optimizer_state state;
+
+ const double C = 1.0;
+ linear_trainer.set_epsilon(1e-10);
+ linear_trainer_cpa.set_epsilon(1e-10);
+
+ linear_trainer.include_bias(false);
+
+
+ std::vector<sample_type> samples, samples_explict_bias;
+ std::vector<double> labels;
+
+ // make an instance of a sample vector so we can use it below
+ sample_type sample;
+
+ decision_function<kernel_type> df, df2, df3;
+
+ dlib::rand rnd;
+ // Now lets go into a loop and randomly generate 10000 samples.
+ double label = +1;
+ for (int i = 0; i < 100; ++i)
+ {
+ // flip this flag
+ label *= -1;
+
+ sample = 0;
+
+ // now make a random sparse sample with at most 10 non-zero elements
+ for (int j = 0; j < 5; ++j)
+ {
+ int idx = rnd.get_random_32bit_number()%9;
+ double value = rnd.get_random_double();
+
+ sample(idx) = label*value;
+ }
+
+ // Also save the samples we are generating so we can let the svm_c_linear_trainer
+ // learn from them below.
+ samples.push_back(sample);
+ labels.push_back(label);
+
+ sample(9) = -1;
+ samples_explict_bias.push_back(sample);
+
+ if (samples.size() > 1)
+ {
+ linear_trainer_cpa.set_c_class1(C);
+ linear_trainer_cpa.set_c_class2(1.5*C);
+ linear_trainer.set_c_class1(C/samples.size());
+ linear_trainer.set_c_class2(1.5*C/samples.size());
+
+ df = linear_trainer.train(samples_explict_bias, labels, state);
+ df2 = linear_trainer_cpa.train(samples, labels);
+ df3 = linear_trainer.train(samples_explict_bias, labels);
+
+ DLIB_TEST( std::abs(df2.basis_vectors(0)(9)) < 1e-7);
+ DLIB_TEST_MSG( max(abs(colm(df.basis_vectors(0),0,9) - colm(df2.basis_vectors(0),0,9))) < 1e-6, max(abs(colm(df.basis_vectors(0),0,9) - colm(df2.basis_vectors(0),0,9))));
+ DLIB_TEST( std::abs(df.basis_vectors(0)(9) - df2.b) < 1e-6);
+ DLIB_TEST( max(abs(df.basis_vectors(0) - df3.basis_vectors(0))) < 1e-6);
+ DLIB_TEST( std::abs(df.b - df3.b) < 1e-7);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_normal()
+ {
+ typedef matrix<double,10,1> sample_type;
+
+
+ typedef linear_kernel<sample_type> kernel_type;
+
+
+
+ svm_c_linear_trainer<kernel_type> linear_trainer_cpa;
+ svm_c_linear_dcd_trainer<kernel_type> linear_trainer;
+
+ svm_c_linear_dcd_trainer<kernel_type>::optimizer_state state;
+
+ const double C = 1;
+ linear_trainer.set_epsilon(1e-10);
+ linear_trainer_cpa.set_epsilon(1e-10);
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ // make an instance of a sample vector so we can use it below
+ sample_type sample;
+
+ decision_function<kernel_type> df, df2, df3;
+
+ dlib::rand rnd;
+ // Now lets go into a loop and randomly generate 10000 samples.
+ double label = +1;
+ for (int i = 0; i < 100; ++i)
+ {
+ // flip this flag
+ label *= -1;
+
+ sample = 0;
+
+ // now make a random sparse sample with at most 10 non-zero elements
+ for (int j = 0; j < 5; ++j)
+ {
+ int idx = rnd.get_random_32bit_number()%10;
+ double value = rnd.get_random_double();
+
+ sample(idx) = label*value;
+ }
+
+ // Also save the samples we are generating so we can let the svm_c_linear_trainer
+ // learn from them below.
+ samples.push_back(sample);
+ labels.push_back(label);
+
+ if (samples.size() > 1)
+ {
+ linear_trainer_cpa.set_c_class1(C);
+ linear_trainer_cpa.set_c_class2(1.5*C);
+ linear_trainer.set_c_class1(C/samples.size());
+ linear_trainer.set_c_class2(1.5*C/samples.size());
+
+ df = linear_trainer.train(samples, labels, state);
+ df2 = linear_trainer_cpa.train(samples, labels);
+ df3 = linear_trainer.train(samples, labels);
+
+ DLIB_TEST_MSG( max(abs(df.basis_vectors(0) - df2.basis_vectors(0))) < 1e-7, max(abs(df.basis_vectors(0) - df2.basis_vectors(0))));
+ DLIB_TEST( std::abs(df.b - df2.b) < 1e-7);
+ DLIB_TEST( max(abs(df.basis_vectors(0) - df3.basis_vectors(0))) < 1e-7);
+ DLIB_TEST( std::abs(df.b - df3.b) < 1e-7);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_normal_force_last_weight(bool have_bias, bool force_weight)
+ {
+ typedef matrix<double,10,1> sample_type;
+ dlog << LINFO << "have_bias: "<< have_bias << " force_weight: "<< force_weight;
+
+
+ typedef linear_kernel<sample_type> kernel_type;
+
+
+ svm_c_linear_trainer<kernel_type> linear_trainer_cpa;
+
+ svm_c_linear_dcd_trainer<kernel_type> linear_trainer;
+
+ svm_c_linear_dcd_trainer<kernel_type>::optimizer_state state;
+
+ const double C = 1;
+ linear_trainer.set_epsilon(1e-10);
+ linear_trainer_cpa.set_epsilon(1e-11);
+
+ linear_trainer_cpa.force_last_weight_to_1(force_weight);
+
+ linear_trainer.force_last_weight_to_1(force_weight);
+ linear_trainer.include_bias(have_bias);
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ // make an instance of a sample vector so we can use it below
+ sample_type sample;
+
+ decision_function<kernel_type> df, df2;
+
+ running_stats<double> rs;
+
+ dlib::rand rnd;
+ // Now lets go into a loop and randomly generate 10000 samples.
+ double label = +1;
+ for (int i = 0; i < 40; ++i)
+ {
+ // flip this flag
+ label *= -1;
+
+ sample = 0;
+
+ // now make a random sparse sample with at most 10 non-zero elements
+ for (int j = 0; j < 5; ++j)
+ {
+ int idx = rnd.get_random_32bit_number()%9;
+ double value = rnd.get_random_double();
+
+ sample(idx) = label*value + label;
+ }
+
+ sample(9) = 4;
+
+ // Also save the samples we are generating so we can let the svm_c_linear_trainer
+ // learn from them below.
+ samples.push_back(sample);
+ labels.push_back(label);
+
+ linear_trainer.set_c(C);
+ linear_trainer_cpa.set_c(C*samples.size());
+
+ df = linear_trainer.train(samples, labels, state);
+
+ if (force_weight)
+ {
+ DLIB_TEST(std::abs(df.basis_vectors(0)(9) - 1) < 1e-8);
+ DLIB_TEST(std::abs(df.b) < 1e-8);
+
+ if (samples.size() > 1)
+ {
+ df2 = linear_trainer_cpa.train(samples, labels);
+ DLIB_TEST_MSG( max(abs(df.basis_vectors(0) - df2.basis_vectors(0))) < 1e-7, max(abs(df.basis_vectors(0) - df2.basis_vectors(0))));
+ DLIB_TEST( std::abs(df.b - df2.b) < 1e-7);
+ }
+ }
+
+ if (!have_bias)
+ DLIB_TEST(std::abs(df.b) < 1e-8);
+
+
+ for (unsigned long k = 0; k < samples.size(); ++k)
+ {
+ //cout << "pred: "<< labels[k]*df(samples[k]) << endl;
+ rs.add(labels[k]*df(samples[k]));
+ }
+ }
+ DLIB_TEST_MSG(std::abs(rs.min()-1) < 1e-7, std::abs(rs.min()-1));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_normal_1_sample(double label)
+ {
+ typedef matrix<double,10,1> sample_type;
+
+
+ typedef linear_kernel<sample_type> kernel_type;
+
+
+
+ svm_c_linear_dcd_trainer<kernel_type> linear_trainer;
+
+ svm_c_linear_dcd_trainer<kernel_type>::optimizer_state state;
+
+ const double C = 10;
+ linear_trainer.set_epsilon(1e-10);
+ linear_trainer.set_c(C);
+
+
+ linear_trainer.force_last_weight_to_1(true);
+ linear_trainer.include_bias(false);
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ // make an instance of a sample vector so we can use it below
+ sample_type sample;
+
+ sample = 0;
+ sample(0) = -1;
+ sample(1) = -1;
+ sample(9) = 4;
+
+ samples.push_back(sample);
+ labels.push_back(label);
+
+ for (int i = 0; i < 4; ++i)
+ {
+ decision_function<kernel_type> df;
+ df = linear_trainer.train(samples, labels);
+
+ if (label > 0)
+ {
+ DLIB_TEST(std::abs(df(samples[0])-4) < 1e-8);
+ }
+ else
+ {
+ DLIB_TEST(std::abs(df(samples[0])+1) < 1e-8);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_sparse_1_sample(double label)
+ {
+ typedef std::vector<std::pair<unsigned long,double> > sample_type;
+
+
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+
+
+
+ svm_c_linear_dcd_trainer<kernel_type> linear_trainer;
+
+ svm_c_linear_dcd_trainer<kernel_type>::optimizer_state state;
+
+ const double C = 10;
+ linear_trainer.set_epsilon(1e-10);
+ linear_trainer.set_c(C);
+
+
+ linear_trainer.force_last_weight_to_1(true);
+ linear_trainer.include_bias(false);
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ // make an instance of a sample vector so we can use it below
+ sample_type sample;
+
+ sample.push_back(make_pair(0,-1));
+ sample.push_back(make_pair(1,1));
+ sample.push_back(make_pair(9,4));
+
+ for (int i = 0; i < 4; ++i)
+ {
+ samples.push_back(sample);
+ labels.push_back(label);
+
+ decision_function<kernel_type> df;
+ df = linear_trainer.train(samples, labels);
+
+
+ if (label > 0)
+ {
+ DLIB_TEST(std::abs(df(samples[0])-4) < 1e-8);
+ }
+ else
+ {
+ DLIB_TEST(std::abs(df(samples[0])+1) < 1e-8);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_l2_version ()
+ {
+ typedef std::map<unsigned long,double> sample_type;
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+
+ svm_c_linear_dcd_trainer<kernel_type> linear_trainer;
+ linear_trainer.set_c(10);
+ linear_trainer.set_epsilon(1e-5);
+
+ std::vector<sample_type> samples;
+ std::vector<double> labels;
+
+ // make an instance of a sample vector so we can use it below
+ sample_type sample;
+
+
+ // Now let's go into a loop and randomly generate 10000 samples.
+ double label = +1;
+ for (int i = 0; i < 1000; ++i)
+ {
+ // flip this flag
+ label *= -1;
+
+ sample.clear();
+
+ // now make a random sparse sample with at most 10 non-zero elements
+ for (int j = 0; j < 10; ++j)
+ {
+ int idx = std::rand()%100;
+ double value = static_cast<double>(std::rand())/RAND_MAX;
+
+ sample[idx] = label*value;
+ }
+
+ // Also save the samples we are generating so we can let the svm_c_linear_trainer
+ // learn from them below.
+ samples.push_back(sample);
+ labels.push_back(label);
+ }
+
+ decision_function<kernel_type> df = linear_trainer.train(samples, labels);
+
+ sample.clear();
+ sample[4] = 0.3;
+ sample[10] = 0.9;
+ DLIB_TEST(df(sample) > 0);
+
+ sample.clear();
+ sample[83] = -0.3;
+ sample[26] = -0.9;
+ sample[58] = -0.7;
+ DLIB_TEST(df(sample) < 0);
+
+ sample.clear();
+ sample[0] = -0.2;
+ sample[9] = -0.8;
+ DLIB_TEST(df(sample) < 0);
+ }
+
+ class tester_svm_c_linear_dcd : public tester
+ {
+ public:
+ tester_svm_c_linear_dcd (
+ ) :
+ tester ("test_svm_c_linear_dcd",
+ "Runs tests on the svm_c_linear_dcd_trainer.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test_normal();
+ print_spinner();
+ test_normal_no_bias();
+ print_spinner();
+ test_sparse();
+ print_spinner();
+ test_normal_force_last_weight(false,false);
+ print_spinner();
+ test_normal_force_last_weight(false,true);
+ print_spinner();
+ test_normal_force_last_weight(true,false);
+ print_spinner();
+ test_normal_force_last_weight(true,true);
+ print_spinner();
+ test_normal_1_sample(+1);
+ print_spinner();
+ test_normal_1_sample(-1);
+ print_spinner();
+ test_sparse_1_sample(+1);
+ print_spinner();
+ test_sparse_1_sample(-1);
+ print_spinner();
+
+ test_l2_version();
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/svm_multiclass_linear.cpp b/ml/dlib/dlib/test/svm_multiclass_linear.cpp
new file mode 100644
index 000000000..e01d48892
--- /dev/null
+++ b/ml/dlib/dlib/test/svm_multiclass_linear.cpp
@@ -0,0 +1,226 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/svm_threaded.h>
+#include <dlib/data_io.h>
+#include "create_iris_datafile.h"
+#include <vector>
+#include <map>
+#include <sstream>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.svm_multiclass_trainer");
+
+
+ class test_svm_multiclass_trainer : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ test_svm_multiclass_trainer (
+ ) :
+ tester (
+ "test_svm_multiclass_trainer", // the command line argument name for this test
+ "Run tests on the svm_multiclass_linear_trainer stuff.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+
+ void test_prior ()
+ {
+ print_spinner();
+ typedef matrix<double,4,1> sample_type;
+ typedef linear_kernel<sample_type> kernel_type;
+
+ std::vector<sample_type> samples;
+ std::vector<int> labels;
+
+ for (int i = 0; i < 4; ++i)
+ {
+ if (i==2)
+ ++i;
+ for (int iter = 0; iter < 5; ++iter)
+ {
+ sample_type samp;
+ samp = 0;
+ samp(i) = 1;
+ samples.push_back(samp);
+ labels.push_back(i);
+ }
+ }
+
+
+ svm_multiclass_linear_trainer<kernel_type,int> trainer;
+
+ multiclass_linear_decision_function<kernel_type,int> df = trainer.train(samples, labels);
+
+ //cout << "test: \n" << test_multiclass_decision_function(df, samples, labels) << endl;
+ //cout << df.weights << endl;
+ //cout << df.b << endl;
+
+ std::vector<sample_type> samples2;
+ std::vector<int> labels2;
+ int i = 2;
+ for (int iter = 0; iter < 5; ++iter)
+ {
+ sample_type samp;
+ samp = 0;
+ samp(i) = 1;
+ samples2.push_back(samp);
+ labels2.push_back(i);
+ samples.push_back(samp);
+ labels.push_back(i);
+ }
+
+ trainer.set_prior(df);
+ trainer.set_c(0.1);
+ df = trainer.train(samples2, labels2);
+
+ matrix<double> res = test_multiclass_decision_function(df, samples, labels);
+ dlog << LINFO << "test: \n" << res;
+ dlog << LINFO << df.weights;
+ dlog << LINFO << df.b;
+ DLIB_TEST((unsigned int)sum(diag(res))==samples.size());
+ }
+
+ void test_prior_sparse ()
+ {
+ print_spinner();
+ typedef std::map<unsigned long,double> sample_type;
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+
+ std::vector<sample_type> samples;
+ std::vector<int> labels;
+
+ for (int i = 0; i < 4; ++i)
+ {
+ if (i==2)
+ ++i;
+ for (int iter = 0; iter < 5; ++iter)
+ {
+ sample_type samp;
+ samp[i] = 1;
+ samples.push_back(samp);
+ labels.push_back(i);
+ }
+ }
+
+
+ svm_multiclass_linear_trainer<kernel_type,int> trainer;
+
+ multiclass_linear_decision_function<kernel_type,int> df = trainer.train(samples, labels);
+
+ //cout << "test: \n" << test_multiclass_decision_function(df, samples, labels) << endl;
+ //cout << df.weights << endl;
+ //cout << df.b << endl;
+
+ std::vector<sample_type> samples2;
+ std::vector<int> labels2;
+ int i = 2;
+ for (int iter = 0; iter < 5; ++iter)
+ {
+ sample_type samp;
+ samp[i] = 1;
+ samp[i+10] = 1;
+ samples2.push_back(samp);
+ labels2.push_back(i);
+ samples.push_back(samp);
+ labels.push_back(i);
+ }
+
+ trainer.set_prior(df);
+ trainer.set_c(0.1);
+ df = trainer.train(samples2, labels2);
+
+ matrix<double> res = test_multiclass_decision_function(df, samples, labels);
+ dlog << LINFO << "test: \n" << res;
+ dlog << LINFO << df.weights;
+ dlog << LINFO << df.b;
+ DLIB_TEST((unsigned int)sum(diag(res))==samples.size());
+ }
+
+ template <typename sample_type>
+ void run_test()
+ {
+ print_spinner();
+
+ typedef typename sample_type::value_type::second_type scalar_type;
+
+ std::vector<sample_type> samples;
+ std::vector<scalar_type> labels;
+
+ load_libsvm_formatted_data("iris.scale",samples, labels);
+
+ DLIB_TEST(samples.size() == 150);
+ DLIB_TEST(labels.size() == 150);
+
+ typedef sparse_linear_kernel<sample_type> kernel_type;
+ svm_multiclass_linear_trainer<kernel_type> trainer;
+ trainer.set_c(100);
+ trainer.set_epsilon(0.000001);
+
+ randomize_samples(samples, labels);
+ matrix<double> cv = cross_validate_multiclass_trainer(trainer, samples, labels, 4);
+
+ dlog << LINFO << "confusion matrix: \n" << cv;
+ const scalar_type cv_accuracy = sum(diag(cv))/sum(cv);
+ dlog << LINFO << "cv accuracy: " << cv_accuracy;
+ DLIB_TEST(cv_accuracy > 0.97);
+
+
+
+
+ {
+ print_spinner();
+ typedef matrix<scalar_type,0,1> dsample_type;
+ std::vector<dsample_type> dsamples = sparse_to_dense(samples);
+ DLIB_TEST(dsamples.size() == 150);
+
+ typedef linear_kernel<dsample_type> kernel_type;
+ svm_multiclass_linear_trainer<kernel_type> trainer;
+ trainer.set_c(100);
+
+ cv = cross_validate_multiclass_trainer(trainer, dsamples, labels, 4);
+
+ dlog << LINFO << "dense confusion matrix: \n" << cv;
+ const scalar_type cv_accuracy = sum(diag(cv))/sum(cv);
+ dlog << LINFO << "dense cv accuracy: " << cv_accuracy;
+ DLIB_TEST(cv_accuracy > 0.97);
+ }
+
+ }
+
+
+
+
+ void perform_test (
+ )
+ {
+ print_spinner();
+ create_iris_datafile();
+
+ run_test<std::map<unsigned int, double> >();
+ run_test<std::map<unsigned int, float> >();
+ run_test<std::vector<std::pair<unsigned int, float> > >();
+ run_test<std::vector<std::pair<unsigned long, double> > >();
+
+ test_prior();
+ test_prior_sparse();
+ }
+ };
+
+ test_svm_multiclass_trainer a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/svm_struct.cpp b/ml/dlib/dlib/test/svm_struct.cpp
new file mode 100644
index 000000000..00208c48d
--- /dev/null
+++ b/ml/dlib/dlib/test/svm_struct.cpp
@@ -0,0 +1,641 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/svm_threaded.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.svm_struct");
+
+
+ template <
+ typename matrix_type,
+ typename sample_type,
+ typename label_type
+ >
+ class test_multiclass_svm_problem : public structural_svm_problem_threaded<matrix_type,
+ std::vector<std::pair<unsigned long,typename matrix_type::type> > >
+ {
+
+ public:
+ typedef typename matrix_type::type scalar_type;
+ typedef std::vector<std::pair<unsigned long,scalar_type> > feature_vector_type;
+
+ test_multiclass_svm_problem (
+ const std::vector<sample_type>& samples_,
+ const std::vector<label_type>& labels_
+ ) :
+ structural_svm_problem_threaded<matrix_type,
+ std::vector<std::pair<unsigned long,typename matrix_type::type> > >(2),
+ samples(samples_),
+ labels(labels_),
+ dims(10+1) // +1 for the bias
+ {
+ for (int i = 0; i < 10; ++i)
+ {
+ distinct_labels.push_back(i);
+ }
+ }
+
+ virtual long get_num_dimensions (
+ ) const
+ {
+ return dims*10;
+ }
+
+ virtual long get_num_samples (
+ ) const
+ {
+ return static_cast<long>(samples.size());
+ }
+
+ virtual void get_truth_joint_feature_vector (
+ long idx,
+ feature_vector_type& psi
+ ) const
+ {
+ assign(psi, samples[idx]);
+ // Add a constant -1 to account for the bias term.
+ psi.push_back(std::make_pair(dims-1,static_cast<scalar_type>(-1)));
+
+ // Find which distinct label goes with this psi.
+ const long label_idx = index_of_max(mat(distinct_labels) == labels[idx]);
+
+ offset_feature_vector(psi, dims*label_idx);
+ }
+
+ virtual void separation_oracle (
+ const long idx,
+ const matrix_type& current_solution,
+ scalar_type& loss,
+ feature_vector_type& psi
+ ) const
+ {
+ scalar_type best_val = -std::numeric_limits<scalar_type>::infinity();
+ unsigned long best_idx = 0;
+
+ // Figure out which label is the best. That is, what label maximizes
+ // LOSS(idx,y) + F(x,y). Note that y in this case is given by distinct_labels[i].
+ for (unsigned long i = 0; i < distinct_labels.size(); ++i)
+ {
+ // Compute the F(x,y) part:
+ // perform: temp == dot(relevant part of current solution, samples[idx]) - current_bias
+ scalar_type temp = dot(rowm(current_solution, range(i*dims, (i+1)*dims-2)), samples[idx]) - current_solution((i+1)*dims-1);
+
+ // Add the LOSS(idx,y) part:
+ if (labels[idx] != distinct_labels[i])
+ temp += 1;
+
+ // Now temp == LOSS(idx,y) + F(x,y). Check if it is the biggest we have seen.
+ if (temp > best_val)
+ {
+ best_val = temp;
+ best_idx = i;
+ }
+ }
+
+ assign(psi, samples[idx]);
+ // add a constant -1 to account for the bias term
+ psi.push_back(std::make_pair(dims-1,static_cast<scalar_type>(-1)));
+
+ offset_feature_vector(psi, dims*best_idx);
+
+ if (distinct_labels[best_idx] == labels[idx])
+ loss = 0;
+ else
+ loss = 1;
+ }
+
+ private:
+
+ void offset_feature_vector (
+ feature_vector_type& sample,
+ const unsigned long val
+ ) const
+ {
+ if (val != 0)
+ {
+ for (typename feature_vector_type::iterator i = sample.begin(); i != sample.end(); ++i)
+ {
+ i->first += val;
+ }
+ }
+ }
+
+
+ const std::vector<sample_type>& samples;
+ const std::vector<label_type>& labels;
+ std::vector<label_type> distinct_labels;
+ const long dims;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename K,
+ typename label_type_ = typename K::scalar_type
+ >
+ class test_svm_multiclass_linear_trainer2
+ {
+ public:
+ typedef label_type_ label_type;
+ typedef K kernel_type;
+ typedef typename kernel_type::scalar_type scalar_type;
+ typedef typename kernel_type::sample_type sample_type;
+ typedef typename kernel_type::mem_manager_type mem_manager_type;
+
+ typedef multiclass_linear_decision_function<kernel_type, label_type> trained_function_type;
+
+
+ test_svm_multiclass_linear_trainer2 (
+ ) :
+ C(10),
+ eps(1e-4),
+ verbose(false)
+ {
+ }
+
+ trained_function_type train (
+ const std::vector<sample_type>& all_samples,
+ const std::vector<label_type>& all_labels
+ ) const
+ {
+ scalar_type svm_objective = 0;
+ return train(all_samples, all_labels, svm_objective);
+ }
+
+ trained_function_type train (
+ const std::vector<sample_type>& all_samples,
+ const std::vector<label_type>& all_labels,
+ scalar_type& svm_objective
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(is_learning_problem(all_samples,all_labels),
+ "\t trained_function_type test_svm_multiclass_linear_trainer2::train(all_samples,all_labels)"
+ << "\n\t invalid inputs were given to this function"
+ << "\n\t all_samples.size(): " << all_samples.size()
+ << "\n\t all_labels.size(): " << all_labels.size()
+ );
+
+ typedef matrix<scalar_type,0,1> w_type;
+ w_type weights;
+ std::vector<sample_type> samples1(all_samples.begin(), all_samples.begin()+all_samples.size()/2);
+ std::vector<sample_type> samples2(all_samples.begin()+all_samples.size()/2, all_samples.end());
+
+ std::vector<label_type> labels1(all_labels.begin(), all_labels.begin()+all_labels.size()/2);
+ std::vector<label_type> labels2(all_labels.begin()+all_labels.size()/2, all_labels.end());
+ test_multiclass_svm_problem<w_type, sample_type, label_type> problem1(samples1, labels1);
+ test_multiclass_svm_problem<w_type, sample_type, label_type> problem2(samples2, labels2);
+ problem1.set_max_cache_size(3);
+ problem2.set_max_cache_size(0);
+
+ svm_struct_processing_node node1(problem1, 12345, 3);
+ svm_struct_processing_node node2(problem2, 12346, 0);
+
+ solver.set_inactive_plane_threshold(50);
+ solver.set_subproblem_epsilon(1e-4);
+
+ svm_struct_controller_node controller;
+ controller.set_c(C);
+ controller.set_epsilon(eps);
+ if (verbose)
+ controller.be_verbose();
+ controller.add_processing_node("127.0.0.1", 12345);
+ controller.add_processing_node("localhost:12346");
+ svm_objective = controller(solver, weights);
+
+
+
+ trained_function_type df;
+
+ const long dims = max_index_plus_one(all_samples);
+ df.labels = select_all_distinct_labels(all_labels);
+ df.weights = colm(reshape(weights, df.labels.size(), dims+1), range(0,dims-1));
+ df.b = colm(reshape(weights, df.labels.size(), dims+1), dims);
+ return df;
+ }
+
+ private:
+ scalar_type C;
+ scalar_type eps;
+ bool verbose;
+ mutable oca solver;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename K,
+ typename label_type_ = typename K::scalar_type
+ >
+ class test_svm_multiclass_linear_trainer3
+ {
+ public:
+ typedef label_type_ label_type;
+ typedef K kernel_type;
+ typedef typename kernel_type::scalar_type scalar_type;
+ typedef typename kernel_type::sample_type sample_type;
+ typedef typename kernel_type::mem_manager_type mem_manager_type;
+
+ typedef multiclass_linear_decision_function<kernel_type, label_type> trained_function_type;
+
+
+ test_svm_multiclass_linear_trainer3 (
+ ) :
+ C(10),
+ eps(1e-4),
+ verbose(false)
+ {
+ }
+
+ trained_function_type train (
+ const std::vector<sample_type>& all_samples,
+ const std::vector<label_type>& all_labels
+ ) const
+ {
+ scalar_type svm_objective = 0;
+ return train(all_samples, all_labels, svm_objective);
+ }
+
+ trained_function_type train (
+ const std::vector<sample_type>& all_samples,
+ const std::vector<label_type>& all_labels,
+ scalar_type& svm_objective
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(is_learning_problem(all_samples,all_labels),
+ "\t trained_function_type test_svm_multiclass_linear_trainer3::train(all_samples,all_labels)"
+ << "\n\t invalid inputs were given to this function"
+ << "\n\t all_samples.size(): " << all_samples.size()
+ << "\n\t all_labels.size(): " << all_labels.size()
+ );
+
+ typedef matrix<scalar_type,0,1> w_type;
+ w_type weights;
+ test_multiclass_svm_problem<w_type, sample_type, label_type> problem(all_samples, all_labels);
+ problem.set_max_cache_size(0);
+
+ problem.set_c(C);
+ problem.set_epsilon(eps);
+
+ if (verbose)
+ problem.be_verbose();
+
+ solver.set_inactive_plane_threshold(50);
+ solver.set_subproblem_epsilon(1e-4);
+ svm_objective = solver(problem, weights);
+
+
+ trained_function_type df;
+
+ const long dims = max_index_plus_one(all_samples);
+ df.labels = select_all_distinct_labels(all_labels);
+ df.weights = colm(reshape(weights, df.labels.size(), dims+1), range(0,dims-1));
+ df.b = colm(reshape(weights, df.labels.size(), dims+1), dims);
+ return df;
+ }
+
+ private:
+ scalar_type C;
+ scalar_type eps;
+ bool verbose;
+ mutable oca solver;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename K,
+ typename label_type_ = typename K::scalar_type
+ >
+ class test_svm_multiclass_linear_trainer4
+ {
+ public:
+ typedef label_type_ label_type;
+ typedef K kernel_type;
+ typedef typename kernel_type::scalar_type scalar_type;
+ typedef typename kernel_type::sample_type sample_type;
+ typedef typename kernel_type::mem_manager_type mem_manager_type;
+
+ typedef multiclass_linear_decision_function<kernel_type, label_type> trained_function_type;
+
+
+ test_svm_multiclass_linear_trainer4 (
+ ) :
+ C(10),
+ eps(1e-4),
+ verbose(false)
+ {
+ }
+
+ trained_function_type train (
+ const std::vector<sample_type>& all_samples,
+ const std::vector<label_type>& all_labels
+ ) const
+ {
+ scalar_type svm_objective = 0;
+ return train(all_samples, all_labels, svm_objective);
+ }
+
+ trained_function_type train (
+ const std::vector<sample_type>& all_samples,
+ const std::vector<label_type>& all_labels,
+ scalar_type& svm_objective
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(is_learning_problem(all_samples,all_labels),
+ "\t trained_function_type test_svm_multiclass_linear_trainer4::train(all_samples,all_labels)"
+ << "\n\t invalid inputs were given to this function"
+ << "\n\t all_samples.size(): " << all_samples.size()
+ << "\n\t all_labels.size(): " << all_labels.size()
+ );
+
+ typedef matrix<scalar_type,0,1> w_type;
+ w_type weights;
+ test_multiclass_svm_problem<w_type, sample_type, label_type> problem(all_samples, all_labels);
+ problem.set_max_cache_size(3);
+
+ problem.set_c(C);
+ problem.set_epsilon(eps);
+
+ if (verbose)
+ problem.be_verbose();
+
+ solver.set_inactive_plane_threshold(50);
+ solver.set_subproblem_epsilon(1e-4);
+ svm_objective = solver(problem, weights);
+
+
+ trained_function_type df;
+
+ const long dims = max_index_plus_one(all_samples);
+ df.labels = select_all_distinct_labels(all_labels);
+ df.weights = colm(reshape(weights, df.labels.size(), dims+1), range(0,dims-1));
+ df.b = colm(reshape(weights, df.labels.size(), dims+1), dims);
+ return df;
+ }
+
+ private:
+ scalar_type C;
+ scalar_type eps;
+ bool verbose;
+ mutable oca solver;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename K,
+ typename label_type_ = typename K::scalar_type
+ >
+ class test_svm_multiclass_linear_trainer5
+ {
+ public:
+ typedef label_type_ label_type;
+ typedef K kernel_type;
+ typedef typename kernel_type::scalar_type scalar_type;
+ typedef typename kernel_type::sample_type sample_type;
+ typedef typename kernel_type::mem_manager_type mem_manager_type;
+
+ typedef multiclass_linear_decision_function<kernel_type, label_type> trained_function_type;
+
+
+ test_svm_multiclass_linear_trainer5 (
+ ) :
+ C(10),
+ eps(1e-4),
+ verbose(false)
+ {
+ }
+
+ trained_function_type train (
+ const std::vector<sample_type>& all_samples,
+ const std::vector<label_type>& all_labels
+ ) const
+ {
+ scalar_type svm_objective = 0;
+ return train(all_samples, all_labels, svm_objective);
+ }
+
+ trained_function_type train (
+ const std::vector<sample_type>& all_samples,
+ const std::vector<label_type>& all_labels,
+ scalar_type& svm_objective
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(is_learning_problem(all_samples,all_labels),
+ "\t trained_function_type test_svm_multiclass_linear_trainer5::train(all_samples,all_labels)"
+ << "\n\t invalid inputs were given to this function"
+ << "\n\t all_samples.size(): " << all_samples.size()
+ << "\n\t all_labels.size(): " << all_labels.size()
+ );
+
+ typedef matrix<scalar_type,0,1> w_type;
+ w_type weights;
+ const long dims = max_index_plus_one(all_samples);
+ trained_function_type df;
+ df.labels = select_all_distinct_labels(all_labels);
+ multiclass_svm_problem<w_type, sample_type, label_type> problem(all_samples, all_labels, df.labels, dims, 4);
+ problem.set_max_cache_size(3);
+
+ problem.set_c(C);
+ problem.set_epsilon(eps);
+
+ if (verbose)
+ problem.be_verbose();
+
+ solver.set_inactive_plane_threshold(50);
+ solver.set_subproblem_epsilon(1e-4);
+ svm_objective = solver(problem, weights);
+
+
+
+ df.weights = colm(reshape(weights, df.labels.size(), dims+1), range(0,dims-1));
+ df.b = colm(reshape(weights, df.labels.size(), dims+1), dims);
+ return df;
+ }
+
+ private:
+ scalar_type C;
+ scalar_type eps;
+ bool verbose;
+ mutable oca solver;
+ };
+
+
+// ----------------------------------------------------------------------------------------
+
+ typedef matrix<double,10,1> sample_type;
+ typedef double scalar_type;
+
+ void make_dataset (
+ std::vector<sample_type>& samples,
+ std::vector<scalar_type>& labels,
+ int num,
+ dlib::rand& rnd
+ )
+ {
+ samples.clear();
+ labels.clear();
+ for (int i = 0; i < 10; ++i)
+ {
+ for (int j = 0; j < num; ++j)
+ {
+ sample_type samp;
+ samp = 0;
+ samp(i) = 10*rnd.get_random_double()+1;
+
+ samples.push_back(samp);
+ labels.push_back(i);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_svm_struct : public tester
+ {
+ public:
+ test_svm_struct (
+ ) :
+ tester ("test_svm_struct",
+ "Runs tests on the structural svm components.")
+ {}
+
+ void run_test (
+ const std::vector<sample_type>& samples,
+ const std::vector<scalar_type>& labels,
+ const double true_obj
+ )
+ {
+ typedef linear_kernel<sample_type> kernel_type;
+ svm_multiclass_linear_trainer<kernel_type> trainer1;
+ test_svm_multiclass_linear_trainer2<kernel_type> trainer2;
+ test_svm_multiclass_linear_trainer3<kernel_type> trainer3;
+ test_svm_multiclass_linear_trainer4<kernel_type> trainer4;
+ test_svm_multiclass_linear_trainer5<kernel_type> trainer5;
+
+ trainer1.set_epsilon(1e-4);
+ trainer1.set_c(10);
+
+
+ multiclass_linear_decision_function<kernel_type,double> df1, df2, df3, df4, df5;
+ double obj1, obj2, obj3, obj4, obj5;
+
+ // Solve a multiclass SVM a whole bunch of different ways and make sure
+ // they all give the same answer.
+ print_spinner();
+ df1 = trainer1.train(samples, labels, obj1);
+ print_spinner();
+ df2 = trainer2.train(samples, labels, obj2);
+ print_spinner();
+ df3 = trainer3.train(samples, labels, obj3);
+ print_spinner();
+ df4 = trainer4.train(samples, labels, obj4);
+ print_spinner();
+ df5 = trainer5.train(samples, labels, obj5);
+ print_spinner();
+
+ dlog << LINFO << "obj1: "<< obj1;
+ dlog << LINFO << "obj2: "<< obj2;
+ dlog << LINFO << "obj3: "<< obj3;
+ dlog << LINFO << "obj4: "<< obj4;
+ dlog << LINFO << "obj5: "<< obj5;
+ DLIB_TEST(std::abs(obj1 - obj2) < 1e-2);
+ DLIB_TEST(std::abs(obj1 - obj3) < 1e-2);
+ DLIB_TEST(std::abs(obj1 - obj4) < 1e-2);
+ DLIB_TEST(std::abs(obj1 - obj5) < 1e-2);
+ DLIB_TEST(std::abs(obj1 - true_obj) < 1e-2);
+ DLIB_TEST(std::abs(obj2 - true_obj) < 1e-2);
+ DLIB_TEST(std::abs(obj3 - true_obj) < 1e-2);
+ DLIB_TEST(std::abs(obj4 - true_obj) < 1e-2);
+ DLIB_TEST(std::abs(obj5 - true_obj) < 1e-2);
+
+ dlog << LINFO << "weight error: "<< max(abs(df1.weights - df2.weights));
+ dlog << LINFO << "weight error: "<< max(abs(df1.weights - df3.weights));
+ dlog << LINFO << "weight error: "<< max(abs(df1.weights - df4.weights));
+ dlog << LINFO << "weight error: "<< max(abs(df1.weights - df5.weights));
+
+ DLIB_TEST(max(abs(df1.weights - df2.weights)) < 1e-2);
+ DLIB_TEST(max(abs(df1.weights - df3.weights)) < 1e-2);
+ DLIB_TEST(max(abs(df1.weights - df4.weights)) < 1e-2);
+ DLIB_TEST(max(abs(df1.weights - df5.weights)) < 1e-2);
+
+ dlog << LINFO << "b error: "<< max(abs(df1.b - df2.b));
+ dlog << LINFO << "b error: "<< max(abs(df1.b - df3.b));
+ dlog << LINFO << "b error: "<< max(abs(df1.b - df4.b));
+ dlog << LINFO << "b error: "<< max(abs(df1.b - df5.b));
+ DLIB_TEST(max(abs(df1.b - df2.b)) < 1e-2);
+ DLIB_TEST(max(abs(df1.b - df3.b)) < 1e-2);
+ DLIB_TEST(max(abs(df1.b - df4.b)) < 1e-2);
+ DLIB_TEST(max(abs(df1.b - df5.b)) < 1e-2);
+
+ matrix<double> res = test_multiclass_decision_function(df1, samples, labels);
+ dlog << LINFO << res;
+ dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res);
+ DLIB_TEST(sum(diag(res)) == samples.size());
+
+ res = test_multiclass_decision_function(df2, samples, labels);
+ dlog << LINFO << res;
+ dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res);
+ DLIB_TEST(sum(diag(res)) == samples.size());
+
+ res = test_multiclass_decision_function(df3, samples, labels);
+ dlog << LINFO << res;
+ dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res);
+ DLIB_TEST(sum(diag(res)) == samples.size());
+
+ res = test_multiclass_decision_function(df4, samples, labels);
+ dlog << LINFO << res;
+ dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res);
+ DLIB_TEST(sum(diag(res)) == samples.size());
+
+ res = test_multiclass_decision_function(df5, samples, labels);
+ dlog << LINFO << res;
+ dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res);
+ DLIB_TEST(sum(diag(res)) == samples.size());
+ }
+
+ void perform_test (
+ )
+ {
+ std::vector<sample_type> samples;
+ std::vector<scalar_type> labels;
+
+ dlib::rand rnd;
+
+ dlog << LINFO << "test with 100 samples per class";
+ make_dataset(samples, labels, 100, rnd);
+ run_test(samples, labels, 1.155);
+
+ dlog << LINFO << "test with 1 sample per class";
+ make_dataset(samples, labels, 1, rnd);
+ run_test(samples, labels, 0.251);
+
+ dlog << LINFO << "test with 2 sample per class";
+ make_dataset(samples, labels, 2, rnd);
+ run_test(samples, labels, 0.444);
+ }
+ } a;
+
+
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/svr_linear_trainer.cpp b/ml/dlib/dlib/test/svr_linear_trainer.cpp
new file mode 100644
index 000000000..ca1a5442f
--- /dev/null
+++ b/ml/dlib/dlib/test/svr_linear_trainer.cpp
@@ -0,0 +1,161 @@
+// Copyright (C) 2013 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/matrix.h>
+#include <sstream>
+#include <string>
+#include <ctime>
+#include <vector>
+#include <dlib/statistics.h>
+
+#include "tester.h"
+#include <dlib/svm.h>
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.svr_linear_trainer");
+
+ typedef matrix<double, 0, 1> sample_type;
+ typedef std::vector<std::pair<unsigned int, double> > sparse_sample_type;
+
+// ----------------------------------------------------------------------------------------
+
+ double sinc(double x)
+ {
+ if (x == 0)
+ return 1;
+ return sin(x)/x;
+ }
+
+ template <typename scalar_type>
+ void test1()
+ {
+ typedef matrix<scalar_type,0,1> sample_type;
+
+ typedef radial_basis_kernel<sample_type> kernel_type;
+
+ print_spinner();
+
+ std::vector<sample_type> samples;
+ std::vector<scalar_type> targets;
+
+ // The first thing we do is pick a few training points from the sinc() function.
+ sample_type m(1);
+ for (scalar_type x = -10; x <= 4; x += 1)
+ {
+ m(0) = x;
+
+ samples.push_back(m);
+ targets.push_back(sinc(x)+1.1);
+ }
+
+ randomize_samples(samples, targets);
+
+ empirical_kernel_map<kernel_type> ekm;
+ ekm.load(kernel_type(0.1), samples);
+
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ samples[i] = ekm.project(samples[i]);
+
+ svr_linear_trainer<linear_kernel<sample_type> > linear_trainer;
+ linear_trainer.set_epsilon(0.0001);
+ linear_trainer.set_c(30);
+ linear_trainer.set_epsilon_insensitivity(0.001);
+
+ matrix<double> res = cross_validate_regression_trainer(linear_trainer, samples, targets, 5);
+ dlog << LINFO << "MSE and R-Squared: "<< res;
+ DLIB_TEST(res(0) < 1e-4);
+ DLIB_TEST(res(1) > 0.99);
+
+ dlib::rand rnd;
+
+ samples.clear();
+ targets.clear();
+ std::vector<scalar_type> noisefree_targets;
+ for (scalar_type x = 0; x <= 5; x += 0.1)
+ {
+ m(0) = x;
+ samples.push_back(matrix_cast<scalar_type>(linpiece(m, linspace(0,5,20))));
+ targets.push_back(x*x + rnd.get_random_gaussian());
+ noisefree_targets.push_back(x*x);
+ }
+ linear_trainer.set_learns_nonnegative_weights(true);
+ linear_trainer.set_epsilon_insensitivity(1.0);
+ decision_function<linear_kernel<sample_type> > df2 = linear_trainer.train(samples, targets);
+
+ print_spinner();
+ res = test_regression_function(df2, samples, noisefree_targets);
+ dlog << LINFO << "MSE and R-Squared: "<< res;
+ DLIB_TEST(res(0) < 0.15);
+ DLIB_TEST(res(1) > 0.98);
+ DLIB_TEST(df2.basis_vectors.size()==1);
+ DLIB_TEST(max(df2.basis_vectors(0)) >= 0);
+
+ linear_trainer.force_last_weight_to_1(true);
+ df2 = linear_trainer.train(samples, targets);
+ DLIB_TEST(std::abs(df2.basis_vectors(0)(samples[0].size()-1) - 1.0) < 1e-14);
+
+ res = test_regression_function(df2, samples, noisefree_targets);
+ dlog << LINFO << "MSE and R-Squared: "<< res;
+ DLIB_TEST(res(0) < 0.20);
+ DLIB_TEST(res(1) > 0.98);
+
+
+ // convert into sparse vectors and try it out
+ typedef std::vector<std::pair<unsigned long, scalar_type> > sparse_samp;
+ std::vector<sparse_samp> ssamples;
+ for (unsigned long i = 0; i < samples.size(); ++i)
+ {
+ sparse_samp s;
+ for (long j = 0; j < samples[i].size(); ++j)
+ s.push_back(make_pair(j,samples[i](j)));
+ ssamples.push_back(s);
+ }
+
+ svr_linear_trainer<sparse_linear_kernel<sparse_samp> > strainer;
+ strainer.set_learns_nonnegative_weights(true);
+ strainer.set_epsilon_insensitivity(1.0);
+ strainer.set_c(30);
+ decision_function<sparse_linear_kernel<sparse_samp> > df;
+ df = strainer.train(ssamples, targets);
+ res = test_regression_function(df, ssamples, noisefree_targets);
+ dlog << LINFO << "MSE and R-Squared: "<< res;
+ DLIB_TEST(res(0) < 0.15);
+ DLIB_TEST(res(1) > 0.98);
+ DLIB_TEST(df2.basis_vectors.size()==1);
+ DLIB_TEST(max(sparse_to_dense(df2.basis_vectors(0))) >= 0);
+ }
+
+
+// ----------------------------------------------------------------------------------------
+
+ class tester_svr_linear_trainer : public tester
+ {
+ public:
+ tester_svr_linear_trainer (
+ ) :
+ tester ("test_svr_linear_trainer",
+ "Runs tests on the svr_linear_trainer.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "TEST double";
+ test1<double>();
+ dlog << LINFO << "TEST float";
+ test1<float>();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/symmetric_matrix_cache.cpp b/ml/dlib/dlib/test/symmetric_matrix_cache.cpp
new file mode 100644
index 000000000..6d93a4daa
--- /dev/null
+++ b/ml/dlib/dlib/test/symmetric_matrix_cache.cpp
@@ -0,0 +1,212 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include "tester.h"
+#include <dlib/matrix.h>
+#include <dlib/rand.h>
+#include <vector>
+#include <sstream>
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ dlib::logger dlog("test.symmetric_matrix_cache");
+
+
+ class test_symmetric_matrix_cache : public tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a unit test. When it is constructed
+ it adds itself into the testing framework.
+ !*/
+ public:
+ test_symmetric_matrix_cache (
+ ) :
+ tester (
+ "test_symmetric_matrix_cache", // the command line argument name for this test
+ "Run tests on the symmetric_matrix_cache function.", // the command line argument description
+ 0 // the number of command line arguments for this test
+ )
+ {
+ }
+
+ dlib::rand rnd;
+
+ // -----------------------------------
+
+ template <typename EXP1, typename EXP2>
+ void test_colm_exp (
+ const matrix_exp<EXP1>& m1,
+ const matrix_exp<EXP2>& m2
+ )
+ {
+ for (long i = 0; i < m1.nc(); ++i)
+ {
+
+ typename colm_exp<EXP1>::type c1 = colm(m1,i);
+ typename colm_exp<EXP2>::type c2 = colm(m2,i);
+
+ DLIB_TEST(equal(c1 , c2));
+ DLIB_TEST(equal(colm(m1,i) , c2));
+ DLIB_TEST(equal(c1 , colm(m2,i)));
+ DLIB_TEST(equal(colm(m1,i) , colm(m2,i)));
+ }
+
+
+ // Get a bunch of columns at once to test out the reference
+ // counting and automatic cache expansion built into the symmetric_matrix_cache.
+ // This test verifies that, for example, getting column 3 doesn't stomp on
+ // any of the previous columns.
+ typename colm_exp<EXP1>::type c1_0 = colm(m1,0);
+ typename colm_exp<EXP1>::type c1_1 = colm(m1,1);
+ typename colm_exp<EXP1>::type c1_2 = colm(m1,2);
+ typename colm_exp<EXP1>::type c1_3 = colm(m1,3);
+ typename colm_exp<EXP1>::type c1_4 = colm(m1,4);
+ typename colm_exp<EXP1>::type c1_5 = colm(m1,5);
+
+ typename colm_exp<EXP2>::type c2_0 = colm(m2,0);
+ typename colm_exp<EXP2>::type c2_1 = colm(m2,1);
+ typename colm_exp<EXP2>::type c2_2 = colm(m2,2);
+ typename colm_exp<EXP2>::type c2_3 = colm(m2,3);
+ typename colm_exp<EXP2>::type c2_4 = colm(m2,4);
+ typename colm_exp<EXP2>::type c2_5 = colm(m2,5);
+
+ DLIB_TEST(equal(c1_0, c2_0));
+ DLIB_TEST(equal(c1_1, c2_1));
+ DLIB_TEST(equal(c1_2, c2_2));
+ DLIB_TEST(equal(c1_3, c2_3));
+ DLIB_TEST(equal(c1_4, c2_4));
+ DLIB_TEST(equal(c1_5, c2_5));
+ }
+
+ // -----------------------------------
+
+ template <typename EXP1, typename EXP2>
+ void test_rowm_exp (
+ const matrix_exp<EXP1>& m1,
+ const matrix_exp<EXP2>& m2
+ )
+ {
+ for (long i = 0; i < m1.nc(); ++i)
+ {
+
+ typename rowm_exp<EXP1>::type r1 = rowm(m1,i);
+ typename rowm_exp<EXP2>::type r2 = rowm(m2,i);
+
+ DLIB_TEST(equal(r1 , r2));
+ DLIB_TEST(equal(rowm(m1,i) , r2));
+ DLIB_TEST(equal(r1 , rowm(m2,i)));
+ DLIB_TEST(equal(rowm(m1,i) , rowm(m2,i)));
+ }
+
+
+ // Get a bunch of rows at once to test out the reference
+ // counting and automatic cache expansion built into the symmetric_matrix_cache.
+ // This test verifies that, for example, getting row 3 doesn't stomp on
+ // any of the previous rows.
+ typename rowm_exp<EXP1>::type r1_0 = rowm(m1,0);
+ typename rowm_exp<EXP1>::type r1_1 = rowm(m1,1);
+ typename rowm_exp<EXP1>::type r1_2 = rowm(m1,2);
+ typename rowm_exp<EXP1>::type r1_3 = rowm(m1,3);
+ typename rowm_exp<EXP1>::type r1_4 = rowm(m1,4);
+ typename rowm_exp<EXP1>::type r1_5 = rowm(m1,5);
+
+ typename rowm_exp<EXP2>::type r2_0 = rowm(m2,0);
+ typename rowm_exp<EXP2>::type r2_1 = rowm(m2,1);
+ typename rowm_exp<EXP2>::type r2_2 = rowm(m2,2);
+ typename rowm_exp<EXP2>::type r2_3 = rowm(m2,3);
+ typename rowm_exp<EXP2>::type r2_4 = rowm(m2,4);
+ typename rowm_exp<EXP2>::type r2_5 = rowm(m2,5);
+
+ DLIB_TEST(equal(r1_0, r2_0));
+ DLIB_TEST(equal(r1_1, r2_1));
+ DLIB_TEST(equal(r1_2, r2_2));
+ DLIB_TEST(equal(r1_3, r2_3));
+ DLIB_TEST(equal(r1_4, r2_4));
+ DLIB_TEST(equal(r1_5, r2_5));
+ }
+
+ // -----------------------------------
+
+ template <typename EXP1, typename EXP2>
+ void test_diag_exp (
+ const matrix_exp<EXP1>& m1,
+ const matrix_exp<EXP2>& m2
+ )
+ {
+
+ typename diag_exp<EXP1>::type c1 = diag(m1);
+ typename diag_exp<EXP2>::type c2 = diag(m2);
+
+ DLIB_TEST(equal(c1 , c2));
+ DLIB_TEST(equal(diag(m1) , c2));
+ DLIB_TEST(equal(c1 , diag(m2)));
+ DLIB_TEST(equal(diag(m1) , diag(m2)));
+ }
+
+ // -----------------------------------
+
+ void test_stuff (
+ long csize
+ )
+ {
+ print_spinner();
+ dlog << LINFO << "csize: "<< csize;
+ matrix<double> m = randm(10,10,rnd);
+
+ m = make_symmetric(m);
+
+ DLIB_TEST(equal(symmetric_matrix_cache<float>(m, csize), matrix_cast<float>(m)));
+ DLIB_TEST(equal(symmetric_matrix_cache<double>(m, csize), matrix_cast<double>(m)));
+
+ dlog << LINFO << "test colm/rowm";
+
+
+ for (long i = 0; i < m.nr(); ++i)
+ {
+ DLIB_TEST(equal(colm(symmetric_matrix_cache<float>(m, csize),i), colm(matrix_cast<float>(m),i)));
+ DLIB_TEST(equal(rowm(symmetric_matrix_cache<float>(m, csize),i), rowm(matrix_cast<float>(m),i)));
+ // things are supposed to be symmetric
+ DLIB_TEST(equal(colm(symmetric_matrix_cache<float>(m, csize),i), trans(rowm(matrix_cast<float>(m),i))));
+ DLIB_TEST(equal(rowm(symmetric_matrix_cache<float>(m, csize),i), trans(colm(matrix_cast<float>(m),i))));
+ }
+
+ dlog << LINFO << "test diag";
+ DLIB_TEST(equal(diag(symmetric_matrix_cache<float>(m,csize)), diag(matrix_cast<float>(m))));
+
+ test_colm_exp(symmetric_matrix_cache<float>(m,csize), matrix_cast<float>(m));
+ test_rowm_exp(symmetric_matrix_cache<float>(m,csize), matrix_cast<float>(m));
+ test_diag_exp(symmetric_matrix_cache<float>(m,csize), matrix_cast<float>(m));
+
+ test_colm_exp(tmp(symmetric_matrix_cache<float>(m,csize)), tmp(matrix_cast<float>(m)));
+ test_rowm_exp(symmetric_matrix_cache<float>(m,csize), tmp(matrix_cast<float>(m)));
+ test_diag_exp(tmp(symmetric_matrix_cache<float>(m,csize)), tmp(matrix_cast<float>(m)));
+ }
+
+
+ void perform_test (
+ )
+ {
+
+ for (int itr = 0; itr < 5; ++itr)
+ {
+ test_stuff(0);
+ test_stuff(1);
+ test_stuff(2);
+ }
+
+ }
+ };
+
+ // Create an instance of this object. Doing this causes this test
+ // to be automatically inserted into the testing framework whenever this cpp file
+ // is linked into the project. Note that since we are inside an unnamed-namespace
+ // we won't get any linker errors about the symbol a being defined multiple times.
+ test_symmetric_matrix_cache a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/tester.cpp b/ml/dlib/dlib/test/tester.cpp
new file mode 100644
index 000000000..2fb4d41ac
--- /dev/null
+++ b/ml/dlib/dlib/test/tester.cpp
@@ -0,0 +1,175 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#include <string>
+#include "tester.h"
+#include <cstdlib>
+#include <dlib/threads.h>
+
+namespace test
+{
+// -----------------------------------------------------------------------------
+
+ bool be_verbose = true;
+
+// -----------------------------------------------------------------------------
+
+ static dlib::mutex spinner_mutex;
+ static dlib::mutex test_count_mutex;
+ dlib::uint64 test_count = 0;
+
+// -----------------------------------------------------------------------------
+
+ dlib::uint64 number_of_testing_statements_executed (
+ )
+ {
+ dlib::auto_mutex lock(test_count_mutex);
+ return test_count;
+ }
+
+ void increment_test_count (
+ )
+ {
+ test_count_mutex.lock();
+ ++test_count;
+ test_count_mutex.unlock();
+ }
+
+// -----------------------------------------------------------------------------
+
+ void check_test (
+ bool _exp,
+ long line,
+ const char* file,
+ const char* _exp_str
+ )
+ {
+ test_count_mutex.lock();
+ ++test_count;
+ test_count_mutex.unlock();
+ if ( !(_exp) )
+ {
+ std::ostringstream dlib_o_out;
+ dlib_o_out << "\n\nError occurred at line " << line << ".\n";
+ dlib_o_out << "Error occurred in file " << file << ".\n";
+ dlib_o_out << "Failing expression was " << _exp_str << ".\n";
+ throw dlib::error(dlib_o_out.str());
+ }
+ }
+
+// -----------------------------------------------------------------------------
+
+ map_of_testers& testers (
+ )
+ {
+ static map_of_testers t;
+ return t;
+ }
+
+// -----------------------------------------------------------------------------
+
+ tester::
+ tester (
+ const std::string& switch_name_x,
+ const std::string& description_x,
+ unsigned long num_of_args_x
+ ) :
+ switch_name(switch_name_x),
+ description_(description_x),
+ num_of_args_(num_of_args_x)
+ {
+ using namespace std;
+ if (testers().is_in_domain(switch_name))
+ {
+ cerr << "ERROR: More than one tester has been defined with the switch '" << switch_name << "'." << endl;
+ exit(1);
+ }
+
+ string temp(switch_name);
+ tester* t = this;
+ testers().add(temp,t);
+ }
+
+// -----------------------------------------------------------------------------
+
+ const std::string& tester::
+ cmd_line_switch (
+ ) const
+ {
+ return switch_name;
+ }
+
+// -----------------------------------------------------------------------------
+
+ const std::string& tester::
+ description (
+ ) const
+ {
+ return description_;
+ }
+
+// -----------------------------------------------------------------------------
+
+ unsigned long tester::
+ num_of_args (
+ ) const
+ {
+ return num_of_args_;
+ }
+
+// -----------------------------------------------------------------------------
+
+ void tester::
+ perform_test (
+ )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+
+ void tester::
+ perform_test (
+ const std::string&
+ )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+
+ void tester::
+ perform_test (
+ const std::string&,
+ const std::string&
+ )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+
+ void print_spinner (
+ )
+ {
+ if (be_verbose)
+ {
+ using namespace std;
+ dlib::auto_mutex M(spinner_mutex);
+ static int i = 0;
+ cout << "\b\b";
+ switch (i)
+ {
+ case 0: cout << '|'; break;
+ case 1: cout << '/'; break;
+ case 2: cout << '-'; break;
+ case 3: cout << '\\'; break;
+ }
+ cout << " " << flush;
+ i = (i+1)%4;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/tester.h b/ml/dlib/dlib/test/tester.h
new file mode 100644
index 000000000..e16647cf5
--- /dev/null
+++ b/ml/dlib/dlib/test/tester.h
@@ -0,0 +1,187 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_TESTEr_
+#define DLIB_TESTEr_
+
+#include <iostream>
+#include <string>
+#include <dlib/map.h>
+#include <dlib/logger.h>
+#include <dlib/assert.h>
+#include <dlib/algs.h>
+#include <typeinfo>
+
+#ifdef __INTEL_COMPILER
+// ignore the bogus warning about not overloading perform_test() all the way
+#pragma warning (disable: 654)
+#endif
+
+
+#define DLIB_TEST(_exp) check_test(bool(_exp), __LINE__, __FILE__, #_exp)
+
+#define DLIB_TEST_MSG(_exp,_message) \
+ do{increment_test_count(); if ( !(_exp) ) \
+ { \
+ std::ostringstream dlib_o_out; \
+ dlib_o_out << "\n\nError occurred at line " << __LINE__ << ".\n"; \
+ dlib_o_out << "Error occurred in file " << __FILE__ << ".\n"; \
+ dlib_o_out << "Failing expression was " << #_exp << ".\n"; \
+ dlib_o_out << _message << "\n"; \
+ throw dlib::error(dlib_o_out.str()); \
+ }}while(0)
+
+namespace test
+{
+ class tester;
+ typedef dlib::map<std::string,tester*>::kernel_1a_c map_of_testers;
+
+ map_of_testers& testers (
+ );
+
+// -----------------------------------------------------------------------------
+
+ void check_test (
+ bool _exp,
+ long line,
+ const char* file,
+ const char* _exp_str
+ );
+
+// -----------------------------------------------------------------------------
+
+// This bool controls any cout statements in this program. Only print to
+// standard out if we should be verbose. The default is true
+ extern bool be_verbose;
+
+// -----------------------------------------------------------------------------
+
+ dlib::uint64 number_of_testing_statements_executed (
+ );
+ /*!
+ ensures
+ - returns the total number of DLIB_TEST and DLIB_TEST_MSG
+ statements executed since program startup.
+ !*/
+
+ void increment_test_count (
+ );
+ /*!
+ ensures
+ - increments number_of_testing_statements_executed()
+ !*/
+
+// -----------------------------------------------------------------------------
+
+ void print_spinner (
+ );
+ /*!
+ ensures
+ - reprints the spinner
+ !*/
+
+// -----------------------------------------------------------------------------
+
+ class tester
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object represents a generic regression test.
+ !*/
+
+ public:
+
+ tester (
+ const std::string& switch_name,
+ const std::string& description_,
+ unsigned long num_of_args_ = 0
+ );
+ /*!
+ requires
+ - testers().is_in_domain(switch_name) == false
+ ensures
+ - #cmd_line_switch() == switch_name
+ - #description() == description_
+ - #num_of_args() == num_of_args_
+ - adds this tester to the testers() map.
+ !*/
+
+ virtual ~tester (
+ ){}
+
+ const std::string& cmd_line_switch (
+ ) const;
+ /*!
+ ensures
+ - returns the name of the command line switch for this tester.
+ !*/
+
+ const std::string& description (
+ ) const;
+ /*!
+ ensures
+ - returns the description of what this tester tests.
+ !*/
+
+ unsigned long num_of_args (
+ ) const;
+ /*!
+ ensures
+ - returns the number of arguments this test expects
+ !*/
+
+ virtual void perform_test (
+ );
+ /*!
+ requires
+ - is invoked when number_of_args() == 0
+ ensures
+ - performs the test and throws an exception
+ derived from std::exception if the test fails.
+ !*/
+
+ virtual void perform_test (
+ const std::string& arg
+ );
+ /*!
+ requires
+ - is invoked when number_of_args() == 1
+ ensures
+ - performs the test and throws an exception
+ derived from std::exception if the test fails.
+ !*/
+
+ virtual void perform_test (
+ const std::string& arg1,
+ const std::string& arg2
+ );
+ /*!
+ requires
+ - is invoked when number_of_args() == 2
+ ensures
+ - performs the test and throws an exception
+ derived from std::exception if the test fails.
+ !*/
+
+ private:
+
+ // ---------------------------------------------------------------------------
+ // Implementation Details
+ // ---------------------------------------------------------------------------
+
+ /*!
+ CONVENTION
+ - switch_name == cmd_line_switch()
+ - description_ == description()
+ - num_of_args_ == num_of_args()
+ - test::tester[switch_name] == this
+ !*/
+
+ const std::string switch_name;
+ const std::string description_;
+ const unsigned long num_of_args_;
+ };
+
+}
+
+#endif // DLIB_TESTEr_
+
diff --git a/ml/dlib/dlib/test/thread_pool.cpp b/ml/dlib/dlib/test/thread_pool.cpp
new file mode 100644
index 000000000..73ccb346e
--- /dev/null
+++ b/ml/dlib/dlib/test/thread_pool.cpp
@@ -0,0 +1,428 @@
+// Copyright (C) 2008 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/misc_api.h>
+#include <dlib/threads.h>
+#include <dlib/any.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.thread_pool");
+
+
+ struct some_struct : noncopyable
+ {
+ float val;
+ };
+
+ int global_var = 0;
+
+ struct add_functor
+ {
+ add_functor() { var = 1;}
+ add_functor(int v):var(v) {}
+
+ template <typename T, typename U, typename V>
+ void operator()(T a, U b, V& res)
+ {
+ dlib::sleep(20);
+ res = a + b;
+ }
+
+ void set_global_var() { global_var = 9; }
+ void set_global_var_const() const { global_var = 9; }
+
+ void set_global_var_arg1(int val) { global_var = val; }
+ void set_global_var_const_arg1(int val) const { global_var = val; }
+ void set_global_var_arg2(int val, int val2) { global_var = val+val2; }
+ void set_global_var_const_arg2(int val, int val2) const { global_var = val+val2; }
+
+ void operator()()
+ {
+ global_var = 9;
+ }
+
+ // use an any just so that if this object goes out of scope
+ // then var will get all messed up.
+ any var;
+ void operator()(int& a) { dlib::sleep(100); a = var.get<int>(); }
+ void operator()(int& a, int& b) { dlib::sleep(100); a = var.get<int>(); b = 2; }
+ void operator()(int& a, int& b, int& c) { dlib::sleep(100); a = var.get<int>(); b = 2; c = 3; }
+ void operator()(int& a, int& b, int& c, int& d) { dlib::sleep(100); a = var.get<int>(); b = 2; c = 3; d = 4; }
+ };
+
+
+ void set_global_var() { global_var = 9; }
+
+ void gset_struct_to_zero (some_struct& a) { a.val = 0; }
+ void gset_to_zero (int& a) { a = 0; }
+ void gincrement (int& a) { ++a; }
+ void gadd (int a, const int& b, int& res) { dlib::sleep(20); res = a + b; }
+ void gadd1(int& a, int& res) { res += a; }
+ void gadd2 (int c, int a, const int& b, int& res) { dlib::sleep(20); res = a + b + c; }
+
+ class thread_pool_tester : public tester
+ {
+ public:
+ thread_pool_tester (
+ ) :
+ tester ("test_thread_pool",
+ "Runs tests on the thread_pool component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ add_functor f;
+ for (int num_threads= 0; num_threads < 4; ++num_threads)
+ {
+ dlib::future<int> a, b, c, res, d;
+ thread_pool tp(num_threads);
+ print_spinner();
+
+ dlib::future<some_struct> obj;
+
+
+ for (int i = 0; i < 4; ++i)
+ {
+ a = 1;
+ b = 2;
+ c = 3;
+ res = 4;
+
+
+ DLIB_TEST(a==a);
+ DLIB_TEST(a!=b);
+ DLIB_TEST(a==1);
+
+ tp.add_task(gset_to_zero, a);
+ tp.add_task(gset_to_zero, b);
+ tp.add_task(*this, &thread_pool_tester::set_to_zero, c);
+ tp.add_task(gset_to_zero, res);
+ DLIB_TEST(a == 0);
+ DLIB_TEST(b == 0);
+ DLIB_TEST(c == 0);
+ DLIB_TEST(res == 0);
+
+
+ tp.add_task(gincrement, a);
+ tp.add_task(*this, &thread_pool_tester::increment, b);
+ tp.add_task(*this, &thread_pool_tester::increment, c);
+ tp.add_task(gincrement, res);
+
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 1);
+ DLIB_TEST(c == 1);
+ DLIB_TEST(res == 1);
+
+ tp.add_task(&gincrement, a);
+ tp.add_task(*this, &thread_pool_tester::increment, b);
+ tp.add_task(*this, &thread_pool_tester::increment, c);
+ tp.add_task(&gincrement, res);
+ tp.add_task(gincrement, a);
+ tp.add_task(*this, &thread_pool_tester::increment, b);
+ tp.add_task(*this, &thread_pool_tester::increment, c);
+ tp.add_task(gincrement, res);
+
+ DLIB_TEST(a == 3);
+ DLIB_TEST(b == 3);
+ DLIB_TEST(c == 3);
+ DLIB_TEST(res == 3);
+
+ tp.add_task(*this, &thread_pool_tester::increment, c);
+ tp.add_task(gincrement, res);
+ DLIB_TEST(c == 4);
+ DLIB_TEST(res == 4);
+
+
+ tp.add_task(gadd, a, b, res);
+ DLIB_TEST(res == a+b);
+ DLIB_TEST(res == 6);
+ a = 3;
+ b = 4;
+ res = 99;
+ DLIB_TEST(res == 99);
+ tp.add_task(*this, &thread_pool_tester::add, a, b, res);
+ DLIB_TEST(res == a+b);
+ DLIB_TEST(res == 7);
+
+ a = 1;
+ b = 2;
+ c = 3;
+ res = 88;
+ DLIB_TEST(res == 88);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(c == 3);
+
+ tp.add_task(gadd2, a, b, c, res);
+ DLIB_TEST(res == 6);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(c == 3);
+
+ a = 1;
+ b = 2;
+ c = 3;
+ res = 88;
+ DLIB_TEST(res == 88);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(c == 3);
+ tp.add_task(*this, &thread_pool_tester::add2, a, b, c, res);
+ DLIB_TEST(res == 6);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(c == 3);
+
+ a = 1;
+ b = 2;
+ c = 3;
+ res = 88;
+ tp.add_task(gadd1, a, b);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 3);
+ a = 2;
+ tp.add_task(*this, &thread_pool_tester::add1, a, b);
+ DLIB_TEST(a == 2);
+ DLIB_TEST(b == 5);
+
+
+ val = 4;
+ uint64 id = tp.add_task(*this, &thread_pool_tester::zero_val);
+ tp.wait_for_task(id);
+ DLIB_TEST(val == 0);
+ id = tp.add_task(*this, &thread_pool_tester::accum2, 1,2);
+ tp.wait_for_all_tasks();
+ DLIB_TEST(val == 3);
+ id = tp.add_task(*this, &thread_pool_tester::accum1, 3);
+ tp.wait_for_task(id);
+ DLIB_TEST(val == 6);
+
+
+ obj.get().val = 8;
+ DLIB_TEST(obj.get().val == 8);
+ tp.add_task(gset_struct_to_zero, obj);
+ DLIB_TEST(obj.get().val == 0);
+ obj.get().val = 8;
+ DLIB_TEST(obj.get().val == 8);
+ tp.add_task(*this,&thread_pool_tester::set_struct_to_zero, obj);
+ DLIB_TEST(obj.get().val == 0);
+
+ a = 1;
+ b = 2;
+ res = 0;
+ tp.add_task(f, a, b, res);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(res == 3);
+
+
+ global_var = 0;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task(&set_global_var);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 9);
+
+ global_var = 0;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task(f);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 9);
+
+ global_var = 0;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task(f, &add_functor::set_global_var);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 9);
+
+ global_var = 0;
+ a = 4;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task(f, &add_functor::set_global_var_arg1, a);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 4);
+
+ global_var = 0;
+ a = 4;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task_by_value(f, &add_functor::set_global_var_arg1, a);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 4);
+
+
+
+ global_var = 0;
+ a = 4;
+ b = 3;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task(f, &add_functor::set_global_var_arg2, a, b);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 7);
+
+ global_var = 0;
+ a = 4;
+ b = 3;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task_by_value(f, &add_functor::set_global_var_arg2, a, b);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 7);
+
+ global_var = 0;
+ a = 4;
+ b = 3;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task(f, &add_functor::set_global_var_const_arg2, a, b);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 7);
+
+ global_var = 0;
+ a = 4;
+ b = 3;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task_by_value(f, &add_functor::set_global_var_const_arg2, a, b);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 7);
+
+
+
+
+
+
+ global_var = 0;
+ a = 4;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task(f, &add_functor::set_global_var_const_arg1, a);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 4);
+
+ global_var = 0;
+ a = 4;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task_by_value(f, &add_functor::set_global_var_const_arg1, a);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 4);
+
+ global_var = 0;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task_by_value(f, &add_functor::set_global_var);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 9);
+
+
+ global_var = 0;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task(f, &add_functor::set_global_var_const);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 9);
+
+
+ global_var = 0;
+ DLIB_TEST(global_var == 0);
+ id = tp.add_task_by_value(f, &add_functor::set_global_var_const);
+ tp.wait_for_task(id);
+ DLIB_TEST(global_var == 9);
+
+
+
+ }
+
+ // add this task just to to perterb the thread pool before it goes out of scope
+ tp.add_task(f, a, b, res);
+
+ for (int k = 0; k < 3; ++k)
+ {
+ print_spinner();
+ global_var = 0;
+ tp.add_task_by_value(add_functor());
+ tp.wait_for_all_tasks();
+ DLIB_TEST(global_var == 9);
+
+ a = 0; b = 0; c = 0; d = 0;
+ tp.add_task_by_value(add_functor(), a);
+ DLIB_TEST(a == 1);
+ a = 0; b = 0; c = 0; d = 0;
+ tp.add_task_by_value(add_functor(8), a, b);
+ DLIB_TEST(a == 8);
+ DLIB_TEST(b == 2);
+ a = 0; b = 0; c = 0; d = 0;
+ tp.add_task_by_value(add_functor(), a, b, c);
+ DLIB_TEST(a == 1);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(c == 3);
+ a = 0; b = 0; c = 0; d = 0;
+ tp.add_task_by_value(add_functor(5), a, b, c, d);
+ DLIB_TEST(a == 5);
+ DLIB_TEST(b == 2);
+ DLIB_TEST(c == 3);
+ DLIB_TEST(d == 4);
+ }
+
+
+ tp.wait_for_all_tasks();
+
+ // make sure exception propagation from tasks works correctly.
+ auto f_throws = []() { throw dlib::error("test exception");};
+ bool got_exception = false;
+ try
+ {
+ tp.add_task_by_value(f_throws);
+ tp.wait_for_all_tasks();
+ }
+ catch(dlib::error& e)
+ {
+ DLIB_TEST(e.info == "test exception");
+ got_exception = true;
+ }
+ DLIB_TEST(got_exception);
+
+ dlib::future<int> aa;
+ auto f_throws2 = [](int& a) { a = 1; throw dlib::error("test exception");};
+ got_exception = false;
+ try
+ {
+ tp.add_task(f_throws2, aa);
+ aa.get();
+ }
+ catch(dlib::error& e)
+ {
+ DLIB_TEST(e.info == "test exception");
+ got_exception = true;
+ }
+ DLIB_TEST(got_exception);
+
+ }
+ }
+
+ long val;
+ void accum1(long a) { val += a; }
+ void accum2(long a, long b) { val += a + b; }
+ void zero_val() { dlib::sleep(20); val = 0; }
+
+
+ void set_struct_to_zero (some_struct& a) { a.val = 0; }
+ void set_to_zero (int& a) { dlib::sleep(20); a = 0; }
+ void increment (int& a) const { dlib::sleep(20); ++a; }
+ void add (int a, const int& b, int& res) { dlib::sleep(20); res = a + b; }
+ void add1(int& a, int& res) const { res += a; }
+ void add2 (int c, int a, const int& b, int& res) { res = a + b + c; }
+
+
+ } a;
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/threads.cpp b/ml/dlib/dlib/test/threads.cpp
new file mode 100644
index 000000000..1aeb1a3f9
--- /dev/null
+++ b/ml/dlib/dlib/test/threads.cpp
@@ -0,0 +1,158 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/misc_api.h>
+#include <dlib/threads.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.threads");
+
+ void test_async()
+ {
+#if __cplusplus >= 201103
+ print_spinner();
+ auto v1 = dlib::async([]() { dlib::sleep(500); return 1; }).share();
+ auto v2 = dlib::async([v1]() { dlib::sleep(400); return v1.get()+1; }).share();
+ auto v3 = dlib::async([v2](int a) { dlib::sleep(300); return v2.get()+a; },2).share();
+ auto v4 = dlib::async([v3]() { dlib::sleep(200); return v3.get()+1; });
+
+ DLIB_TEST(v4.get() == 5);
+
+ print_spinner();
+ auto except = dlib::async([](){ dlib::sleep(300); throw error("oops"); });
+ bool got_exception = false;
+ try
+ {
+ except.get();
+ }
+ catch (error&e)
+ {
+ got_exception = true;
+ DLIB_TEST(e.what() == string("oops"));
+ }
+ DLIB_TEST(got_exception);
+#endif
+ }
+
+ class threads_tester : public tester
+ {
+ public:
+ threads_tester (
+ ) :
+ tester ("test_threads",
+ "Runs tests on the threads component."),
+ sm(cm)
+ {}
+
+ thread_specific_data<int> tsd;
+ rmutex cm;
+ rsignaler sm;
+ int count;
+ bool failure;
+
+ void perform_test (
+ )
+ {
+ failure = false;
+ print_spinner();
+
+
+ count = 10;
+ if (!create_new_thread<threads_tester,&threads_tester::thread1>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread2>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread3>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread4>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread5>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread6>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread7>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread8>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread9>(*this)) failure = true;
+ if (!create_new_thread<threads_tester,&threads_tester::thread10>(*this)) failure = true;
+
+ thread(66);
+
+ // this should happen in the main program thread
+ if (is_dlib_thread())
+ failure = true;
+
+ auto_mutex M(cm);
+ while (count > 0 && !failure)
+ sm.wait();
+
+
+ DLIB_TEST(!failure);
+
+ test_async();
+ }
+
+ void thread_end_handler (
+ )
+ {
+ auto_mutex M(cm);
+ --count;
+ if (count == 0)
+ sm.signal();
+ }
+
+ void thread1() { thread(1); }
+ void thread2()
+ {
+ thread(2);
+ if (is_dlib_thread() == false)
+ failure = true;
+ }
+ void thread3() { thread(3); }
+ void thread4() { thread(4); }
+ void thread5() { thread(5); }
+ void thread6() { thread(6); }
+ void thread7() { thread(7); }
+ void thread8() { thread(8); }
+ void thread9() { thread(9); }
+ void thread10() { thread(10); }
+
+ void thread (
+ int num
+ )
+ {
+ dlog << LTRACE << "starting thread num " << num;
+ if (is_dlib_thread())
+ register_thread_end_handler(*this,&threads_tester::thread_end_handler);
+ tsd.data() = num;
+ for (int i = 0; i < 0x3FFFF; ++i)
+ {
+ if ((i&0xFFF) == 0)
+ {
+ print_spinner();
+ dlib::sleep(10);
+ }
+ // if this isn't equal to num then there is a problem with the thread specific data stuff
+ if (tsd.data() != num)
+ {
+ auto_mutex M(cm);
+ failure = true;
+ sm.signal();
+ }
+ }
+ dlog << LTRACE << "ending of thread num " << num;
+
+
+ }
+ } a;
+
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/timer.cpp b/ml/dlib/dlib/test/timer.cpp
new file mode 100644
index 000000000..ae004a55d
--- /dev/null
+++ b/ml/dlib/dlib/test/timer.cpp
@@ -0,0 +1,347 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+
+#include <dlib/timer.h>
+#include <dlib/timeout.h>
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.timer");
+
+ class timer_test_helper
+ {
+ public:
+ dlib::mutex m;
+ int count;
+ dlib::uint64 timestamp;
+ dlib::timestamper ts;
+
+ timer_test_helper():count(0), timestamp(0){}
+ void add()
+ {
+ m.lock();
+ ++count;
+ m.unlock();
+ }
+
+ void delayed_add()
+ {
+ dlib::sleep(1000);
+ print_spinner();
+ add();
+ }
+
+ void set_timestamp()
+ {
+ m.lock();
+ timestamp = ts.get_timestamp();
+ dlog << LTRACE << "in set_timestamp(), time is " << timestamp;
+ dlib::sleep(1);
+ print_spinner();
+ m.unlock();
+ }
+ };
+
+ template <
+ typename timer_t
+ >
+ void timer_test2 (
+ )
+ /*!
+ requires
+ - timer_t is an implementation of dlib/timer/timer_abstract.h is instantiated
+ timer_test_helper
+ ensures
+ - runs tests on timer_t for compliance with the specs
+ !*/
+ {
+ for (int j = 0; j < 4; ++j)
+ {
+ print_spinner();
+ timer_test_helper h;
+
+ timer_t t1(h,&timer_test_helper::set_timestamp);
+ t1.set_delay_time(0);
+ dlog << LTRACE << "t1.start()";
+ t1.start();
+
+ dlib::sleep(60);
+ print_spinner();
+ t1.stop_and_wait();
+
+ dlib::uint64 cur_time = h.ts.get_timestamp();
+ dlog << LTRACE << "get current time: " << cur_time;
+
+ // make sure the action function has been called recently
+ DLIB_TEST_MSG((cur_time-h.timestamp)/1000 < 30, (cur_time-h.timestamp)/1000);
+
+ }
+ }
+
+ template <
+ typename timer_t
+ >
+ void timer_test (
+ )
+ /*!
+ requires
+ - timer_t is an implementation of dlib/timer/timer_abstract.h is instantiated
+ timer_test_helper
+ ensures
+ - runs tests on timer_t for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+ for (int j = 0; j < 3; ++j)
+ {
+ timer_test_helper h;
+
+ timer_t t1(h,&timer_test_helper::add);
+ timer_t t2(h,&timer_test_helper::add);
+ timer_t t3(h,&timer_test_helper::add);
+
+ DLIB_TEST(t1.delay_time() == 1000);
+ DLIB_TEST(t2.delay_time() == 1000);
+ DLIB_TEST(t3.delay_time() == 1000);
+ DLIB_TEST(t1.is_running() == false);
+ DLIB_TEST(t2.is_running() == false);
+ DLIB_TEST(t3.is_running() == false);
+ DLIB_TEST(t1.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t2.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t3.action_function() == &timer_test_helper::add);
+ DLIB_TEST(&t1.action_object() == &h);
+ DLIB_TEST(&t2.action_object() == &h);
+ DLIB_TEST(&t3.action_object() == &h);
+
+ t1.set_delay_time(1000);
+ t2.set_delay_time(500);
+ t3.set_delay_time(1500);
+
+ DLIB_TEST(t1.delay_time() == 1000);
+ DLIB_TEST(t2.delay_time() == 500);
+ DLIB_TEST(t3.delay_time() == 1500);
+ DLIB_TEST(t1.is_running() == false);
+ DLIB_TEST(t2.is_running() == false);
+ DLIB_TEST(t3.is_running() == false);
+ DLIB_TEST(t1.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t2.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t3.action_function() == &timer_test_helper::add);
+ DLIB_TEST(&t1.action_object() == &h);
+ DLIB_TEST(&t2.action_object() == &h);
+ DLIB_TEST(&t3.action_object() == &h);
+ dlib::sleep(1100);
+ print_spinner();
+ DLIB_TEST(h.count == 0);
+
+ t1.stop_and_wait();
+ t2.stop_and_wait();
+ t3.stop_and_wait();
+
+ dlib::sleep(1100);
+ print_spinner();
+ DLIB_TEST(h.count == 0);
+ DLIB_TEST(t1.delay_time() == 1000);
+ DLIB_TEST(t2.delay_time() == 500);
+ DLIB_TEST(t3.delay_time() == 1500);
+ DLIB_TEST(t1.is_running() == false);
+ DLIB_TEST(t2.is_running() == false);
+ DLIB_TEST(t3.is_running() == false);
+ DLIB_TEST(t1.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t2.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t3.action_function() == &timer_test_helper::add);
+ DLIB_TEST(&t1.action_object() == &h);
+ DLIB_TEST(&t2.action_object() == &h);
+ DLIB_TEST(&t3.action_object() == &h);
+
+ t1.start();
+ t2.start();
+ t3.start();
+
+ DLIB_TEST(t1.delay_time() == 1000);
+ DLIB_TEST(t2.delay_time() == 500);
+ DLIB_TEST(t3.delay_time() == 1500);
+ DLIB_TEST(t1.is_running() == true);
+ DLIB_TEST(t2.is_running() == true);
+ DLIB_TEST(t3.is_running() == true);
+ DLIB_TEST(t1.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t2.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t3.action_function() == &timer_test_helper::add);
+ DLIB_TEST(&t1.action_object() == &h);
+ DLIB_TEST(&t2.action_object() == &h);
+ DLIB_TEST(&t3.action_object() == &h);
+
+ t1.stop();
+ t2.stop();
+ t3.stop();
+
+ DLIB_TEST(t1.delay_time() == 1000);
+ DLIB_TEST(t2.delay_time() == 500);
+ DLIB_TEST(t3.delay_time() == 1500);
+ DLIB_TEST(t1.is_running() == false);
+ DLIB_TEST(t2.is_running() == false);
+ DLIB_TEST(t3.is_running() == false);
+ DLIB_TEST(t1.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t2.action_function() == &timer_test_helper::add);
+ DLIB_TEST(t3.action_function() == &timer_test_helper::add);
+ DLIB_TEST(&t1.action_object() == &h);
+ DLIB_TEST(&t2.action_object() == &h);
+ DLIB_TEST(&t3.action_object() == &h);
+
+ DLIB_TEST(h.count == 0);
+ dlib::sleep(1100);
+ print_spinner();
+ DLIB_TEST(h.count == 0);
+
+ for (int i = 1; i <= 3; ++i)
+ {
+ t1.start();
+ t2.start();
+ t3.start();
+
+ DLIB_TEST(t1.is_running() == true);
+ DLIB_TEST(t2.is_running() == true);
+ DLIB_TEST(t3.is_running() == true);
+
+ dlib::sleep(1800);
+ print_spinner();
+ // this should allow the timers to trigger 5 times
+ t1.stop();
+ t2.stop();
+ t3.stop();
+
+ DLIB_TEST_MSG(h.count == 5*i,"h.count: " << h.count << " i: " << i);
+ dlib::sleep(1100);
+ DLIB_TEST_MSG(h.count == 5*i,"h.count: " << h.count << " i: " << i);
+ }
+
+
+ t1.stop_and_wait();
+
+ h.count = 0;
+ t1.start();
+ dlib::sleep(300);
+ print_spinner();
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ t1.set_delay_time(400);
+ dlib::sleep(200);
+ print_spinner();
+ DLIB_TEST_MSG(h.count == 1,h.count);
+ dlib::sleep(250);
+ print_spinner();
+ DLIB_TEST_MSG(h.count == 1,h.count);
+ dlib::sleep(100);
+ print_spinner();
+ DLIB_TEST_MSG(h.count == 2,h.count);
+ t1.set_delay_time(2000);
+ DLIB_TEST_MSG(h.count == 2,h.count);
+ dlib::sleep(1000);
+ print_spinner();
+ DLIB_TEST_MSG(h.count == 2,h.count);
+ t1.clear();
+
+ h.count = 0;
+ t3.start();
+ DLIB_TEST(t3.is_running() == true);
+ DLIB_TEST(t3.delay_time() == 1500);
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ t3.clear();
+ DLIB_TEST(t3.is_running() == false);
+ DLIB_TEST(t3.delay_time() == 1000);
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ dlib::sleep(200);
+ print_spinner();
+ DLIB_TEST(t3.is_running() == false);
+ DLIB_TEST(t3.delay_time() == 1000);
+ DLIB_TEST_MSG(h.count == 0,h.count);
+
+
+ {
+ h.count = 0;
+ timer_t t4(h,&timer_test_helper::delayed_add);
+ t4.set_delay_time(100);
+ t4.start();
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ dlib::sleep(400);
+ print_spinner();
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ t4.stop_and_wait();
+ DLIB_TEST_MSG(h.count == 1,h.count);
+ DLIB_TEST(t4.is_running() == false);
+ }
+
+ {
+ h.count = 0;
+ timer_t t4(h,&timer_test_helper::delayed_add);
+ t4.set_delay_time(100);
+ t4.start();
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ dlib::sleep(400);
+ print_spinner();
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ t4.clear();
+ DLIB_TEST(t4.is_running() == false);
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ t4.stop_and_wait();
+ DLIB_TEST_MSG(h.count == 1,h.count);
+ DLIB_TEST(t4.is_running() == false);
+ }
+
+ {
+ h.count = 0;
+ timer_t t5(h,&timer_test_helper::delayed_add);
+ t5.set_delay_time(100);
+ t5.start();
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ dlib::sleep(400);
+ print_spinner();
+ DLIB_TEST_MSG(h.count == 0,h.count);
+ }
+ DLIB_TEST_MSG(h.count == 1,h.count);
+
+ }
+
+ }
+
+
+
+
+ class timer_tester : public tester
+ {
+ public:
+ timer_tester (
+ ) :
+ tester ("test_timer",
+ "Runs tests on the timer component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing timer_heavy with test_timer";
+ timer_test<timer_heavy<timer_test_helper> > ();
+ dlog << LINFO << "testing timer_heavy with test_timer2";
+ timer_test2<timer_heavy<timer_test_helper> > ();
+
+ dlog << LINFO << "testing timer with test_timer";
+ timer_test<timer<timer_test_helper> > ();
+ dlog << LINFO << "testing timer with test_timer2";
+ timer_test2<timer<timer_test_helper> > ();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/tokenizer.cpp b/ml/dlib/dlib/test/tokenizer.cpp
new file mode 100644
index 000000000..95a95a7e1
--- /dev/null
+++ b/ml/dlib/dlib/test/tokenizer.cpp
@@ -0,0 +1,378 @@
+// Copyright (C) 2005 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <string>
+#include <sstream>
+
+#include <dlib/tokenizer.h>
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace std;
+ using namespace dlib;
+
+ logger dlog("test.tokenizer");
+
+ template <
+ typename tok
+ >
+ void tokenizer_kernel_test (
+ )
+ /*!
+ requires
+ - tok is an implementation of tokenizer_kernel_abstract.h
+ ensures
+ - runs tests on tok for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ tok test;
+
+ DLIB_TEST(test.numbers() == "0123456789");
+ DLIB_TEST(test.uppercase_letters() == "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ DLIB_TEST(test.lowercase_letters() == "abcdefghijklmnopqrstuvwxyz");
+
+ DLIB_TEST_MSG(test.get_identifier_body() == "_" + test.lowercase_letters() +
+ test.uppercase_letters() + test.numbers(),"");
+ DLIB_TEST_MSG(test.get_identifier_head() == "_" + test.lowercase_letters() +
+ test.uppercase_letters(),"");
+
+ DLIB_TEST(test.stream_is_set() == false);
+ test.clear();
+ DLIB_TEST(test.stream_is_set() == false);
+
+ DLIB_TEST_MSG(test.get_identifier_body() == "_" + test.lowercase_letters() +
+ test.uppercase_letters() + test.numbers(),"");
+ DLIB_TEST_MSG(test.get_identifier_head() == "_" + test.lowercase_letters() +
+ test.uppercase_letters(),"");
+
+ tok test2;
+
+ ostringstream sout;
+ istringstream sin;
+ test2.set_stream(sin);
+
+ DLIB_TEST(test2.stream_is_set());
+ DLIB_TEST(&test2.get_stream() == &sin);
+
+ int type;
+ string token;
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::END_OF_FILE);
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::END_OF_FILE);
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::END_OF_FILE);
+
+
+ sin.clear();
+ sin.str(" The cat 123asdf1234 ._ \n test.");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ DLIB_TEST(test2.peek_type() == tok::IDENTIFIER);
+ DLIB_TEST(test2.peek_token() == "The");
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "The");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "cat");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::NUMBER);
+ DLIB_TEST_MSG(token == "123","token: " << token);
+
+ DLIB_TEST(test2.peek_type() == tok::IDENTIFIER);
+ DLIB_TEST(test2.peek_token() == "asdf1234");
+ DLIB_TEST(test2.peek_type() == tok::IDENTIFIER);
+ DLIB_TEST(test2.peek_token() == "asdf1234");
+ DLIB_TEST(test2.peek_type() == tok::IDENTIFIER);
+ DLIB_TEST(test2.peek_token() == "asdf1234");
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "asdf1234");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == " ","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::CHAR);
+ DLIB_TEST_MSG(token == ".","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "_");
+
+ DLIB_TEST(test2.peek_type() == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(test2.peek_token() == " ","token: \"" << token << "\"" <<
+ "\ntoken size: " << (unsigned int)token.size());
+
+ swap(test,test2);
+
+ DLIB_TEST(test2.stream_is_set() == false);
+
+ DLIB_TEST(test.peek_type() == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(test.peek_token() == " ","token: \"" << token << "\"" <<
+ "\ntoken size: " << (unsigned int)token.size());
+ test.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == " ","token: \"" << token << "\"" <<
+ "\ntoken size: " << (unsigned int)token.size());
+
+ test.get_token(type,token);
+ DLIB_TEST_MSG(type == tok::END_OF_LINE,"token: " << token);
+ DLIB_TEST_MSG(token == "\n","token: " << token);
+
+ swap(test,test2);
+ DLIB_TEST(test.stream_is_set() == false);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == " ","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST_MSG(token == "test","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::CHAR);
+ DLIB_TEST_MSG(token == ".","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::END_OF_FILE);
+
+
+
+
+
+
+
+
+
+
+ test2.set_identifier_token("_" + test.uppercase_letters() +
+ test.lowercase_letters(),test.numbers() + "_" + test.uppercase_letters()
+ +test.lowercase_letters());
+
+
+ sin.clear();
+ sin.str(" The cat 123asdf1234 ._ \n\r test.");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "The");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "cat");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::NUMBER);
+ DLIB_TEST_MSG(token == "123","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "asdf1234");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == " ","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::CHAR);
+ DLIB_TEST_MSG(token == ".","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "_");
+
+ swap(test,test2);
+
+ DLIB_TEST(test2.stream_is_set() == false);
+
+ test.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == " ","token: \"" << token << "\"" <<
+ "\ntoken size: " << (unsigned int)token.size());
+
+ test.get_token(type,token);
+ DLIB_TEST_MSG(type == tok::END_OF_LINE,"token: " << token);
+ DLIB_TEST_MSG(token == "\n","token: " << token);
+
+ swap(test,test2);
+ DLIB_TEST(test.stream_is_set() == false);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == "\r ","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST_MSG(token == "test","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::CHAR);
+ DLIB_TEST_MSG(token == ".","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::END_OF_FILE);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test2.set_identifier_token(test.uppercase_letters() +
+ test.lowercase_letters(),test.numbers() + test.uppercase_letters()
+ +test.lowercase_letters());
+
+
+ sin.clear();
+ sin.str(" The cat 123as_df1234 ._ \n test.");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "The");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "cat");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST(token == " ");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::NUMBER);
+ DLIB_TEST_MSG(token == "123","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "as");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::CHAR);
+ DLIB_TEST_MSG(token == "_","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST(token == "df1234");
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == " ","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::CHAR);
+ DLIB_TEST_MSG(token == ".","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::CHAR);
+ DLIB_TEST(token == "_");
+
+ swap(test,test2);
+
+ DLIB_TEST(test2.stream_is_set() == false);
+
+ test.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == " ","token: \"" << token << "\"" <<
+ "\ntoken size: " << (unsigned int)token.size());
+
+ test.get_token(type,token);
+ DLIB_TEST_MSG(type == tok::END_OF_LINE,"token: " << token);
+ DLIB_TEST_MSG(token == "\n","token: " << token);
+
+ swap(test,test2);
+ DLIB_TEST(test.stream_is_set() == false);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::WHITE_SPACE);
+ DLIB_TEST_MSG(token == " ","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::IDENTIFIER);
+ DLIB_TEST_MSG(token == "test","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::CHAR);
+ DLIB_TEST_MSG(token == ".","token: " << token);
+
+ test2.get_token(type,token);
+ DLIB_TEST(type == tok::END_OF_FILE);
+
+
+ }
+
+
+
+
+
+ class tokenizer_tester : public tester
+ {
+ public:
+ tokenizer_tester (
+ ) :
+ tester ("test_tokenizer",
+ "Runs tests on the tokenizer component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "testing kernel_1a";
+ tokenizer_kernel_test<tokenizer::kernel_1a> ();
+ dlog << LINFO << "testing kernel_1a_c";
+ tokenizer_kernel_test<tokenizer::kernel_1a_c>();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/tools/CMakeLists.txt b/ml/dlib/dlib/test/tools/CMakeLists.txt
new file mode 100644
index 000000000..adbd43cb9
--- /dev/null
+++ b/ml/dlib/dlib/test/tools/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+add_subdirectory(../../../tools/imglab imglab_build)
+add_subdirectory(../../../tools/htmlify htmlify_build)
+add_subdirectory(../../../tools/convert_dlib_nets_to_caffe convert_dlib_nets_to_caffe_build)
diff --git a/ml/dlib/dlib/test/trust_region.cpp b/ml/dlib/dlib/test/trust_region.cpp
new file mode 100644
index 000000000..aa2775b9c
--- /dev/null
+++ b/ml/dlib/dlib/test/trust_region.cpp
@@ -0,0 +1,329 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/optimization.h>
+#include "optimization_test_functions.h"
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+#include "../rand.h"
+
+#include "tester.h"
+
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+ using namespace dlib::test_functions;
+
+ logger dlog("test.trust_region");
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T>
+ struct neg_rosen_model
+ {
+ typedef matrix<T,0,1> column_vector;
+ typedef matrix<T,0,0> general_matrix;
+
+ T operator() ( column_vector x) const
+ {
+ return -static_cast<T>(rosen<T>(x));
+ }
+
+ void get_derivative_and_hessian (
+ const column_vector& x,
+ column_vector& d,
+ general_matrix& h
+ ) const
+ {
+ d = -matrix_cast<T>(rosen_derivative<T>(x));
+ h = -matrix_cast<T>(rosen_hessian<T>(x));
+ }
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ dlib::rand rnd;
+
+ template <typename T>
+ void test_with_rosen()
+ {
+ print_spinner();
+
+ matrix<T,2,1> ans;
+ ans = 1,1;
+
+ matrix<T,2,1> p = 100*matrix_cast<T>(randm(2,1,rnd)) - 50;
+
+ T obj = find_min_trust_region(objective_delta_stop_strategy(1e-12, 100), rosen_function_model<T>(), p);
+
+ DLIB_TEST_MSG(std::abs(obj) < 1e-10, "obj: " << obj);
+ DLIB_TEST_MSG(length(p-ans) < 1e-5, "length(p): " << length(p-ans));
+
+ matrix<T,0,1> p2 = 100*matrix_cast<T>(randm(2,1,rnd)) - 50;
+ obj = find_max_trust_region(objective_delta_stop_strategy(1e-12, 100), neg_rosen_model<T>(), p2);
+
+ DLIB_TEST_MSG(std::abs(obj) < 1e-10, "obj: " << obj);
+ DLIB_TEST_MSG(length(p-ans) < 1e-5, "length(p): " << length(p-ans));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_trust_region_sub_problem()
+ {
+ dlog << LINFO << "subproblem test 1";
+ {
+ matrix<double,2,2> B;
+ B = 1, 0,
+ 0, 1;
+
+ matrix<double,2,1> g, p, ans;
+ g = 0;
+
+ ans = 0;
+
+ solve_trust_region_subproblem(B,g,1,p, 0.001, 10);
+
+ DLIB_TEST(length(p-ans) < 1e-10);
+ solve_trust_region_subproblem(B,g,1,p, 0.001, 1);
+ DLIB_TEST(length(p-ans) < 1e-10);
+ }
+
+ dlog << LINFO << "subproblem test 2";
+ {
+ matrix<double,2,2> B;
+ B = 1, 0,
+ 0, 1;
+
+ B *= 0.1;
+
+ matrix<double,2,1> g, p, ans;
+ g = 1;
+
+ ans = -g / length(g);
+
+ solve_trust_region_subproblem(B,g,1,p, 1e-6, 20);
+
+ DLIB_TEST(length(p-ans) < 1e-4);
+ }
+
+ dlog << LINFO << "subproblem test 3";
+ {
+ matrix<double,2,2> B;
+ B = 0, 0,
+ 0, 0;
+
+ matrix<double,2,1> g, p, ans;
+ g = 1;
+
+ ans = -g / length(g);
+
+ solve_trust_region_subproblem(B,g,1,p, 1e-6, 20);
+
+ dlog << LINFO << "ans: " << trans(ans);
+ dlog << LINFO << "p: " << trans(p);
+ DLIB_TEST(length(p-ans) < 1e-4);
+ }
+ return;
+
+ dlog << LINFO << "subproblem test 4";
+ {
+ matrix<double,2,2> B;
+ B = 2, 0,
+ 0, -1;
+
+
+ matrix<double,2,1> g, p, ans;
+ g = 0;
+
+ ans = 0, -1;
+
+ solve_trust_region_subproblem(B,g,1,p, 1e-6, 20);
+
+ DLIB_TEST(length(p-ans) < 1e-4);
+ }
+
+
+ dlog << LINFO << "subproblem test 5";
+ {
+ matrix<double,2,2> B;
+ B = 2, 0,
+ 0, -1;
+
+
+ matrix<double,2,1> g, p, ans;
+ g = 0, 1;
+
+ ans = 0, -1;
+
+ solve_trust_region_subproblem(B,g,1,p, 1e-6, 20);
+
+ DLIB_TEST(length(p-ans) < 1e-4);
+ }
+
+ dlog << LINFO << "subproblem test 6";
+ for (int i = 0; i < 10; ++i)
+ {
+ matrix<double,10,10> B;
+
+ B = randm(10,10, rnd);
+
+ B = 0.01*B*trans(B);
+
+
+ matrix<double,10,1> g, p, ans;
+ g = 1;
+
+ solve_trust_region_subproblem(B,g,1,p, 1e-6, 20);
+
+ DLIB_TEST(std::abs(length(p) - 1) < 1e-4);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void test_problems()
+ {
+ print_spinner();
+ {
+ matrix<double,4,1> ch;
+
+ ch = brown_start();
+
+ find_min_trust_region(objective_delta_stop_strategy(1e-7, 80),
+ brown_function_model(),
+ ch);
+
+ dlog << LINFO << "brown obj: " << brown(ch);
+ dlog << LINFO << "brown der: " << length(brown_derivative(ch));
+ dlog << LINFO << "brown error: " << length(ch - brown_solution());
+
+ DLIB_TEST(length(ch - brown_solution()) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,2,1> ch;
+
+ ch = rosen_start<double>();
+
+ find_min_trust_region(objective_delta_stop_strategy(1e-7, 80),
+ rosen_function_model<double>(),
+ ch);
+
+ dlog << LINFO << "rosen obj: " << rosen(ch);
+ dlog << LINFO << "rosen der: " << length(rosen_derivative(ch));
+ dlog << LINFO << "rosen error: " << length(ch - rosen_solution<double>());
+
+ DLIB_TEST(length(ch - rosen_solution<double>()) < 1e-5);
+ }
+
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(2);
+
+ find_min_trust_region(objective_delta_stop_strategy(1e-7, 80),
+ chebyquad_function_model(),
+ ch);
+
+ dlog << LINFO << "chebyquad 2 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 2 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 2 error: " << length(ch - chebyquad_solution(2));
+
+ DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(4);
+
+ find_min_trust_region(objective_delta_stop_strategy(1e-7, 80),
+ chebyquad_function_model(),
+ ch);
+
+ dlog << LINFO << "chebyquad 4 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 4 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 4 error: " << length(ch - chebyquad_solution(4));
+
+ DLIB_TEST(length(ch - chebyquad_solution(4)) < 1e-5);
+ }
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(6);
+
+ find_min_trust_region(objective_delta_stop_strategy(1e-12, 80),
+ chebyquad_function_model(),
+ ch);
+
+ dlog << LINFO << "chebyquad 6 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 6 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 6 error: " << length(ch - chebyquad_solution(6));
+
+ DLIB_TEST(length(ch - chebyquad_solution(6)) < 1e-5);
+
+ }
+ print_spinner();
+ {
+ matrix<double,0,1> ch;
+
+ ch = chebyquad_start(8);
+
+ find_min_trust_region(objective_delta_stop_strategy(1e-10, 80),
+ chebyquad_function_model(),
+ ch);
+
+ dlog << LINFO << "chebyquad 8 obj: " << chebyquad(ch);
+ dlog << LINFO << "chebyquad 8 der: " << length(chebyquad_derivative(ch));
+ dlog << LINFO << "chebyquad 8 error: " << length(ch - chebyquad_solution(8));
+
+ DLIB_TEST(length(ch - chebyquad_solution(8)) < 1e-5);
+ }
+
+ }
+
+
+
+ class optimization_tester : public tester
+ {
+ public:
+ optimization_tester (
+ ) :
+ tester ("test_trust_region",
+ "Runs tests on the trust region optimization component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ dlog << LINFO << "test with rosen<float>";
+ for (int i = 0; i < 50; ++i)
+ test_with_rosen<float>();
+
+ dlog << LINFO << "test with rosen<double>";
+ for (int i = 0; i < 50; ++i)
+ test_with_rosen<double>();
+
+
+ test_trust_region_sub_problem();
+
+ test_problems();
+ }
+ } a;
+
+}
+
+
diff --git a/ml/dlib/dlib/test/tuple.cpp b/ml/dlib/dlib/test/tuple.cpp
new file mode 100644
index 000000000..da7a18ec8
--- /dev/null
+++ b/ml/dlib/dlib/test/tuple.cpp
@@ -0,0 +1,186 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/tuple.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.tuple");
+
+ struct s_nil
+ {
+ template <typename T>
+ void operator() (
+ const T&
+ ) const
+ {
+ }
+ };
+
+
+ struct inc
+ {
+ template <typename T>
+ void operator() (
+ T& a
+ ) const
+ {
+ a += 1;
+ }
+ };
+
+
+ template <typename T>
+ void check_const (
+ const T& t
+ )
+ {
+ t.template get<0>();
+
+ typedef typename T::template get_type<0>::type type0;
+ t.template get<type0>();
+ t.template index<type0>();
+ }
+
+ template <typename T>
+ void check_nonconst (
+ T& t
+ )
+ {
+ t.template get<0>();
+
+ typedef typename T::template get_type<0>::type type0;
+ t.template get<type0>();
+ t.template index<type0>();
+ }
+
+ void tuple_test (
+ )
+ /*!
+ ensures
+ - runs tests on tuple functions for compliance with the specs
+ !*/
+ {
+
+ print_spinner();
+
+ using dlib::tuple;
+
+ tuple<> a;
+ tuple<int> b;
+ tuple<int, float> c;
+
+
+ a.get<1>();
+ a.get<2>();
+ a.get<3>();
+ a.get<4>();
+ a.get<5>();
+
+ check_nonconst(b);
+ check_nonconst(c);
+ check_const(b);
+ check_const(c);
+
+ COMPILE_TIME_ASSERT((is_same_type<tuple<>::get_type<0>::type, null_type>::value));
+ COMPILE_TIME_ASSERT((is_same_type<tuple<int>::get_type<0>::type, int>::value));
+ COMPILE_TIME_ASSERT((is_same_type<tuple<int,float>::get_type<0>::type, int>::value));
+ COMPILE_TIME_ASSERT((is_same_type<tuple<int,float>::get_type<1>::type, float>::value));
+ COMPILE_TIME_ASSERT((is_same_type<tuple<int,float>::get_type<2>::type, null_type>::value));
+
+ b.get<0>() = 8;
+ DLIB_TEST(b.get<int>() == 8);
+ DLIB_TEST(b.index<int>() == 0);
+
+ c.get<0>() = 9;
+ DLIB_TEST(c.get<int>() == 9);
+ DLIB_TEST(c.index<int>() == 0);
+ c.get<1>() = 3.0;
+ DLIB_TEST(c.get<float>() == 3.0);
+ DLIB_TEST(c.index<float>() == 1);
+
+
+
+ {
+ typedef tuple<int, short, long> T;
+ T a, b;
+ a.get<0>() = 1;
+ a.get<1>() = 3;
+ a.get<2>() = 2;
+
+ b = a;
+
+ inc i;
+ s_nil n;
+ a.for_each(inc());
+ a.for_each(i);
+ const_cast<const T&>(a).for_each(s_nil());
+ const_cast<const T&>(a).for_each(n);
+
+ DLIB_TEST(a.get<0>() == b.get<0>()+2);
+ DLIB_TEST(a.get<1>() == b.get<1>()+2);
+ DLIB_TEST(a.get<2>() == b.get<2>()+2);
+
+ ostringstream sout;
+
+ serialize(a,sout);
+ istringstream sin(sout.str());
+ deserialize(b,sin);
+
+ DLIB_TEST(a.get<0>() == b.get<0>());
+ DLIB_TEST(a.get<1>() == b.get<1>());
+ DLIB_TEST(a.get<2>() == b.get<2>());
+
+ a.for_index(i,0);
+ a.for_index(inc(),1);
+ const_cast<const T&>(a).for_index(n,2);
+ const_cast<const T&>(a).for_index(s_nil(),0);
+
+ DLIB_TEST(a.get<0>() == b.get<0>()+1);
+ DLIB_TEST(a.get<1>() == b.get<1>()+1);
+ DLIB_TEST(a.get<2>() == b.get<2>()+0);
+
+ swap(a,b);
+
+ DLIB_TEST(b.get<0>() == a.get<0>()+1);
+ DLIB_TEST(b.get<1>() == a.get<1>()+1);
+ DLIB_TEST(b.get<2>() == a.get<2>()+0);
+ }
+
+
+ }
+
+
+
+
+ class tuple_tester : public tester
+ {
+ public:
+ tuple_tester (
+ ) :
+ tester ("test_tuple",
+ "Runs tests on the tuple object")
+ {}
+
+ void perform_test (
+ )
+ {
+ tuple_test();
+ }
+ } a;
+
+}
+
+
+
diff --git a/ml/dlib/dlib/test/type_safe_union.cpp b/ml/dlib/dlib/test/type_safe_union.cpp
new file mode 100644
index 000000000..6a18fa8e1
--- /dev/null
+++ b/ml/dlib/dlib/test/type_safe_union.cpp
@@ -0,0 +1,455 @@
+// Copyright (C) 2009 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <dlib/type_safe_union.h>
+
+#include "tester.h"
+
+namespace
+{
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+ logger dlog("test.type_safe_union");
+
+ struct can_not_copy: noncopyable {};
+ void serialize(const can_not_copy&, std::ostream&) {}
+ void deserialize(can_not_copy&, std::istream&) {}
+
+ void swap(can_not_copy&, can_not_copy&) {}
+
+ class test
+ {
+
+ private:
+
+ enum kind
+ {
+ FLOAT, DOUBLE, CHAR, STRING, NONE
+ };
+
+ void operator() (float val)
+ {
+ DLIB_TEST(val == f_val);
+ last_kind = FLOAT;
+ }
+
+ void operator() (double val)
+ {
+ DLIB_TEST(val == d_val);
+ last_kind = DOUBLE;
+ }
+
+ void operator() (char val)
+ {
+ DLIB_TEST(val == c_val);
+ last_kind = CHAR;
+ }
+
+ void operator()(std::string& val)
+ {
+ DLIB_TEST(val == s_val);
+ last_kind = STRING;
+ }
+
+ void operator()(const std::string& val)
+ {
+ DLIB_TEST(val == s_val);
+ last_kind = STRING;
+ }
+
+ // ------------------------------
+
+ friend class type_safe_union<float, double, char, std::string>;
+ typedef type_safe_union<float, double, char, std::string> tsu;
+ tsu a, b, c;
+
+ float f_val;
+ double d_val;
+ char c_val;
+ std::string s_val;
+
+ kind last_kind;
+
+ public:
+ void test_stuff()
+ {
+ DLIB_TEST(a.is_empty() == true);
+ DLIB_TEST(a.contains<char>() == false);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(a.contains<double>() == false);
+ DLIB_TEST(a.contains<std::string>() == false);
+ DLIB_TEST(a.contains<long>() == false);
+
+ DLIB_TEST(a.get_type_id<int>() == -1);
+ DLIB_TEST(a.get_type_id<float>() == 1);
+ DLIB_TEST(a.get_type_id<double>() == 2);
+ DLIB_TEST(a.get_type_id<char>() == 3);
+ DLIB_TEST(a.get_type_id<std::string>() == 4);
+ DLIB_TEST(a.get_type_id<tsu>() == -1);
+
+
+ f_val = 4.345f;
+ a.get<float>() = f_val;
+ DLIB_TEST(a.cast_to<float>() == f_val);
+ DLIB_TEST(const_cast<const tsu&>(a).cast_to<float>() == f_val);
+ bool exception_thrown = false;
+ try {a.cast_to<char>(); }
+ catch (bad_type_safe_union_cast&) { exception_thrown = true;}
+ DLIB_TEST(exception_thrown);
+
+
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<char>() == false);
+ DLIB_TEST(a.contains<float>() == true);
+ DLIB_TEST(a.contains<double>() == false);
+ DLIB_TEST(a.contains<std::string>() == false);
+ DLIB_TEST(a.contains<long>() == false);
+
+
+ last_kind = NONE;
+ const_cast<const tsu&>(a).apply_to_contents(*this);
+ DLIB_TEST(last_kind == FLOAT);
+
+ // -----------
+
+ d_val = 4.345;
+ a.get<double>() = d_val;
+ last_kind = NONE;
+ a.apply_to_contents(*this);
+ DLIB_TEST(last_kind == DOUBLE);
+
+ // -----------
+
+ c_val = 'a';
+ a.get<char>() = c_val;
+ last_kind = NONE;
+ const_cast<const tsu&>(a).apply_to_contents(*this);
+ DLIB_TEST(last_kind == CHAR);
+
+ // -----------
+
+ s_val = "test string";
+ a.get<std::string>() = s_val;
+ last_kind = NONE;
+ a.apply_to_contents(*this);
+ DLIB_TEST(last_kind == STRING);
+
+ DLIB_TEST(a.cast_to<std::string>() == s_val);
+ exception_thrown = false;
+ try {a.cast_to<float>(); }
+ catch (bad_type_safe_union_cast&) { exception_thrown = true;}
+ DLIB_TEST(exception_thrown);
+
+ // -----------
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<char>() == false);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(a.contains<double>() == false);
+ DLIB_TEST(a.contains<std::string>() == true);
+ DLIB_TEST(a.contains<long>() == false);
+ // -----------
+
+ a.swap(b);
+
+ DLIB_TEST(a.is_empty() == true);
+ DLIB_TEST(a.contains<char>() == false);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(a.contains<double>() == false);
+ DLIB_TEST(a.contains<std::string>() == false);
+ DLIB_TEST(a.contains<long>() == false);
+
+ DLIB_TEST(b.is_empty() == false);
+ DLIB_TEST(b.contains<char>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+ DLIB_TEST(b.contains<double>() == false);
+ DLIB_TEST(b.contains<std::string>() == true);
+ DLIB_TEST(b.contains<long>() == false);
+
+
+ last_kind = NONE;
+ b.apply_to_contents(*this);
+ DLIB_TEST(last_kind == STRING);
+
+ // -----------
+
+ b.swap(a);
+
+ DLIB_TEST(b.is_empty() == true);
+ DLIB_TEST(b.contains<char>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+ DLIB_TEST(b.contains<double>() == false);
+ DLIB_TEST(b.contains<std::string>() == false);
+ DLIB_TEST(b.contains<long>() == false);
+
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<char>() == false);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(a.contains<double>() == false);
+ DLIB_TEST(a.contains<std::string>() == true);
+ DLIB_TEST(a.contains<long>() == false);
+
+
+ last_kind = NONE;
+ a.apply_to_contents(*this);
+ DLIB_TEST(last_kind == STRING);
+ last_kind = NONE;
+ b.apply_to_contents(*this);
+ DLIB_TEST(last_kind == NONE);
+
+
+ a.get<char>() = 'a';
+ b.get<char>() = 'b';
+
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<char>() == true);
+ DLIB_TEST(b.is_empty() == false);
+ DLIB_TEST(b.contains<char>() == true);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+
+
+ DLIB_TEST(a.get<char>() == 'a');
+ DLIB_TEST(b.get<char>() == 'b');
+
+ swap(a,b);
+
+
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<char>() == true);
+ DLIB_TEST(b.is_empty() == false);
+ DLIB_TEST(b.contains<char>() == true);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+
+ DLIB_TEST(a.get<char>() == 'b');
+ DLIB_TEST(b.get<char>() == 'a');
+
+ // -----------
+
+ a.get<char>() = 'a';
+ b.get<std::string>() = "a string";
+
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<char>() == true);
+ DLIB_TEST(b.is_empty() == false);
+ DLIB_TEST(b.contains<char>() == false);
+ DLIB_TEST(a.contains<std::string>() == false);
+ DLIB_TEST(b.contains<std::string>() == true);
+
+
+ DLIB_TEST(a.get<char>() == 'a');
+ DLIB_TEST(b.get<std::string>() == "a string");
+
+ swap(a,b);
+
+ DLIB_TEST(b.is_empty() == false);
+ DLIB_TEST(b.contains<char>() == true);
+ DLIB_TEST(a.is_empty() == false);
+ DLIB_TEST(a.contains<char>() == false);
+ DLIB_TEST(b.contains<std::string>() == false);
+ DLIB_TEST(a.contains<std::string>() == true);
+
+
+ DLIB_TEST(b.get<char>() == 'a');
+ DLIB_TEST(a.get<std::string>() == "a string");
+
+
+
+
+ {
+ type_safe_union<char, float, std::string> a, b, empty_union;
+
+ ostringstream sout;
+ istringstream sin;
+
+ a.get<char>() = 'd';
+
+ serialize(a, sout);
+
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+ DLIB_TEST(b.contains<int>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+ DLIB_TEST(b.contains<char>() == true);
+ DLIB_TEST(b.get<char>() == 'd');
+
+ DLIB_TEST(a.contains<int>() == false);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(a.contains<char>() == true);
+ DLIB_TEST(a.get<char>() == 'd');
+
+ sin.clear();
+ sout.clear();
+ sout.str("");
+
+ a.get<std::string>() = "davis";
+
+ serialize(a, sout);
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+
+ DLIB_TEST(b.contains<int>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+ DLIB_TEST(b.contains<std::string>() == true);
+ DLIB_TEST(b.get<std::string>() == "davis");
+
+ sin.clear();
+ sout.clear();
+ sout.str("");
+
+ serialize(empty_union, sout);
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+ DLIB_TEST(b.is_empty() == true);
+
+ }
+
+ {
+ type_safe_union<char, float, std::string> a, b, empty_union;
+
+ ostringstream sout;
+ istringstream sin;
+
+ a = 'd';
+
+ serialize(a, sout);
+
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+ DLIB_TEST(b.contains<int>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+ DLIB_TEST(b.contains<char>() == true);
+ DLIB_TEST(b.get<char>() == 'd');
+
+ DLIB_TEST(a.contains<int>() == false);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(a.contains<char>() == true);
+ DLIB_TEST(a.get<char>() == 'd');
+
+ sin.clear();
+ sout.clear();
+ sout.str("");
+
+ a = std::string("davis");
+
+ serialize(a, sout);
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+
+ DLIB_TEST(b.contains<int>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+ DLIB_TEST(b.contains<std::string>() == true);
+ DLIB_TEST(b.get<std::string>() == "davis");
+
+ sin.clear();
+ sout.clear();
+ sout.str("");
+
+ serialize(empty_union, sout);
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+ DLIB_TEST(b.is_empty() == true);
+
+ }
+
+ {
+ typedef type_safe_union<char, float, std::string, can_not_copy> tsu_type;
+ tsu_type a('d'), aa(std::string("davis")), b, empty_union;
+
+ ostringstream sout;
+ istringstream sin;
+
+
+ serialize(a, sout);
+
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+ DLIB_TEST(b.contains<int>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+ DLIB_TEST(b.contains<char>() == true);
+ DLIB_TEST(b.get<char>() == 'd');
+
+ DLIB_TEST(a.contains<int>() == false);
+ DLIB_TEST(a.contains<float>() == false);
+ DLIB_TEST(a.contains<char>() == true);
+ DLIB_TEST(a.get<char>() == 'd');
+
+ DLIB_TEST(aa.contains<int>() == false);
+ DLIB_TEST(aa.contains<float>() == false);
+ DLIB_TEST(aa.contains<char>() == false);
+ DLIB_TEST(aa.contains<std::string>() == true);
+
+ sin.clear();
+ sout.clear();
+ sout.str("");
+
+
+ serialize(aa, sout);
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+
+ DLIB_TEST(b.contains<int>() == false);
+ DLIB_TEST(b.contains<float>() == false);
+ DLIB_TEST(b.contains<std::string>() == true);
+ DLIB_TEST(b.get<std::string>() == "davis");
+
+ sin.clear();
+ sout.clear();
+ sout.str("");
+
+ serialize(empty_union, sout);
+ sin.str(sout.str());
+ deserialize(b, sin);
+
+ DLIB_TEST(b.is_empty() == true);
+
+ a.get<can_not_copy>();
+ DLIB_TEST(a.contains<can_not_copy>() == true);
+
+ }
+ }
+
+ };
+
+
+
+ class type_safe_union_tester : public tester
+ {
+ public:
+ type_safe_union_tester (
+ ) :
+ tester ("test_type_safe_union",
+ "Runs tests on the type_safe_union object")
+ {}
+
+ void perform_test (
+ )
+ {
+ for (int i = 0; i < 10; ++i)
+ {
+ test a;
+ a.test_stuff();
+ }
+ }
+ } a;
+
+}
+
+
+
+
diff --git a/ml/dlib/dlib/test/vectorstream.cpp b/ml/dlib/dlib/test/vectorstream.cpp
new file mode 100644
index 000000000..a955961a2
--- /dev/null
+++ b/ml/dlib/dlib/test/vectorstream.cpp
@@ -0,0 +1,142 @@
+// Copyright (C) 2012 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+
+#include <dlib/vectorstream.h>
+
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+
+#include "tester.h"
+
+namespace
+{
+
+ using namespace test;
+ using namespace dlib;
+ using namespace std;
+
+
+ logger dlog("test.vectorstream");
+
+// ----------------------------------------------------------------------------------------
+
+ void test1()
+ {
+ print_spinner();
+
+ std::vector<char> buf;
+ vectorstream s(buf);
+
+ for (int i = -1000; i <= 1000; ++i)
+ {
+ char ch = i;
+ s.put(ch);
+ }
+
+ DLIB_TEST(buf.size() == 2001);
+
+ int cnt = -1000;
+ for (unsigned long i = 0; i < buf.size(); ++i)
+ {
+ char ch = cnt;
+ DLIB_TEST(buf[i] == ch);
+ ++cnt;
+ }
+
+ for (int i = -1000; i <= 1000; ++i)
+ {
+ DLIB_TEST(s.peek() != EOF);
+ char ch1 = i;
+ char ch2 = s.get();
+ DLIB_TEST(ch1 == ch2);
+ }
+
+ DLIB_TEST(s.peek() == EOF);
+ DLIB_TEST(s.get() == EOF);
+
+ s.clear();
+ s.seekg(6);
+
+ for (int i = -1000+6; i <= 1000; ++i)
+ {
+ DLIB_TEST(s.peek() != EOF);
+ char ch1 = i;
+ char ch2 = s.get();
+ DLIB_TEST(ch1 == ch2);
+ }
+
+ DLIB_TEST(s.peek() == EOF);
+ DLIB_TEST(s.get() == EOF);
+
+ std::string temp;
+ temp = "one two three!";
+
+ s.seekg(0);
+ buf.clear();
+ s.clear();
+
+ serialize(temp, s);
+ std::string temp2;
+ deserialize(temp2, s);
+ DLIB_TEST(temp2 == temp);
+
+ s.put('1');
+ s.put('2');
+ s.put('3');
+ s.put('4');
+ DLIB_TEST(s.get() == '1');
+ DLIB_TEST(s.get() == '2');
+ DLIB_TEST(s.get() == '3');
+ DLIB_TEST(s.get() == '4');
+
+ s.putback('4');
+ DLIB_TEST(s.get() == '4');
+ s.putback('4');
+ s.putback('3');
+ s.putback('2');
+ s.putback('1');
+ DLIB_TEST(s.get() == '1');
+ DLIB_TEST(s.get() == '2');
+ DLIB_TEST(s.get() == '3');
+ DLIB_TEST(s.get() == '4');
+ DLIB_TEST(s.good() == true);
+ DLIB_TEST(s.get() == EOF);
+ DLIB_TEST(s.good() == false);
+
+ // make sure seeking to a crazy offset doesn't mess things up
+ s.clear();
+ s.seekg(1000000);
+ DLIB_TEST(s.get() == EOF);
+ DLIB_TEST(s.good() == false);
+ s.clear();
+ s.seekg(1000000);
+ char sbuf[100];
+ s.read(sbuf, sizeof(sbuf));
+ DLIB_TEST(s.good() == false);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ class test_vectorstream : public tester
+ {
+ public:
+ test_vectorstream (
+ ) :
+ tester ("test_vectorstream",
+ "Runs tests on the vectorstream component.")
+ {}
+
+ void perform_test (
+ )
+ {
+ test1();
+ }
+ } a;
+
+}
+
+