diff options
Diffstat (limited to 'ml/dlib/dlib/test')
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; + +} + + |